/// <summary>
        /// Evaluates the expression, if possible.
        /// </summary>
        /// <returns> The result of evaluating the expression, or <c>null</c> if the expression can
        /// not be evaluated. </returns>
        public override object Evaluate()
        {
            // Evaluate the operands.
            object left = this.Left.Evaluate();

            if (left == null)
            {
                return(null);
            }

            object right;

            if (OperatorType == OperatorType.In)
            {
                right = null;

                if (ResolvedPrototype == null)
                {
                    return(null);
                }
            }
            else
            {
                right = this.Right.Evaluate();

                if (right == null)
                {
                    return(null);
                }
            }

            // Apply the binary operator logic.
            switch (this.OperatorType)
            {
            case OperatorType.Add:
            {
                var leftPrimitive  = TypeConverter.ToPrimitive(left, PrimitiveTypeHint.None);
                var rightPrimitive = TypeConverter.ToPrimitive(right, PrimitiveTypeHint.None);
                if (TypeUtilities.IsString(leftPrimitive) == true || TypeUtilities.IsString(rightPrimitive) == true)
                {
                    return(TypeConverter.ToString(leftPrimitive) + TypeConverter.ToString(rightPrimitive));
                }
                return(TypeConverter.ToNumber(leftPrimitive) + TypeConverter.ToNumber(rightPrimitive));
            }

            // Arithmetic operations.
            case OperatorType.Subtract:
                return(TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right));

            case OperatorType.Multiply:
                return(TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right));

            case OperatorType.Divide:
                return(TypeConverter.ToNumber(left) / TypeConverter.ToNumber(right));

            case OperatorType.Modulo:
                return(TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right));

            // Bitwise operations.
            case OperatorType.BitwiseAnd:
                return(TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right));

            case OperatorType.BitwiseOr:
                return(TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right));

            case OperatorType.BitwiseXor:
                return(TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right));

            case OperatorType.LeftShift:
                return(TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F));

            case OperatorType.SignedRightShift:
                return(TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F));

            case OperatorType.UnsignedRightShift:
                return((uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F));

            // Relational operations.
            case OperatorType.LessThan:
                return(TypeComparer.LessThan(left, right));

            case OperatorType.LessThanOrEqual:
                return(TypeComparer.LessThanOrEqual(left, right));

            case OperatorType.GreaterThan:
                return(TypeComparer.GreaterThan(left, right));

            case OperatorType.GreaterThanOrEqual:
                return(TypeComparer.GreaterThanOrEqual(left, right));

            // Equality operations.
            case OperatorType.Equal:
                return(TypeComparer.Equals(left, right) == true);

            case OperatorType.StrictlyEqual:
                return(TypeComparer.StrictEquals(left, right) == true);

            case OperatorType.NotEqual:
                return(TypeComparer.Equals(left, right) == false);

            case OperatorType.StrictlyNotEqual:
                return(TypeComparer.StrictEquals(left, right) == false);

            // Logical operations.
            case OperatorType.LogicalAnd:
                if (TypeConverter.ToBoolean(left) == false)
                {
                    return(left);
                }
                return(right);

            case OperatorType.LogicalOr:
                if (TypeConverter.ToBoolean(left) == true)
                {
                    return(left);
                }
                return(right);

            // Misc
            case OperatorType.In:

                // Constant property! Convert it to a string:
                string propertyName = TypeConverter.ToString(left);

                // Exists?
                return(ResolvedPrototype.GetProperty(propertyName) != null);

            case OperatorType.InstanceOf:
                return(null);

            default:
                throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType));
            }
        }
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Literals cannot have side-effects so if a return value is not expected then generate
            // nothing.
            if (optimizationInfo.RootExpression == this)
            {
                return;
            }

            if (this.Value is int)
            {
                generator.LoadInt32((int)this.Value);
            }
            else if (this.Value is double)
            {
                generator.LoadDouble((double)this.Value);
            }
            else if (this.Value is string)
            {
                generator.LoadString((string)this.Value);
            }
            else if (this.Value is bool)
            {
                generator.LoadBoolean((bool)this.Value);
            }
            else if (this.Value is RegularExpressionLiteral)
            {
                // RegExp
                var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value);
                var label1 = generator.CreateLabel();
                var label2 = generator.CreateLabel();

                // if (sharedRegExp == null) {
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.BranchIfNotEqual(label1);

                // sharedRegExp = Global.RegExp.OnConstruct(source, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Flags);
                generator.Call(ReflectionHelpers.RegExp_Construct);
                generator.Duplicate();
                generator.StoreVariable(sharedRegExpVariable);

                // } else {
                generator.Branch(label2);
                generator.DefineLabelPosition(label1);

                // Global.RegExp.OnConstruct(sharedRegExp, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.Call(ReflectionHelpers.RegExp_Construct);

                // }
                generator.DefineLabelPosition(label2);
            }
            else if (this.Value == Null.Value)
            {
                // Null.
                EmitHelpers.EmitNull(generator);
            }
            else if (this.Value == Undefined.Value)
            {
                // Undefined.
                EmitHelpers.EmitUndefined(generator);
            }
            else if (this.Value is List <Expression> )
            {
                // Construct an array literal.
                var arrayLiteral = (List <Expression>) this.Value;

                // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[])
                // ArrayConstructor
                EmitHelpers.LoadEngine(generator);

                // object[]
                generator.LoadInt32(arrayLiteral.Count);
                generator.NewArray(typeof(object));

                for (int i = 0; i < arrayLiteral.Count; i++)
                {
                    // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object).
                    // Array
                    generator.Duplicate();

                    // Index
                    generator.LoadInt32(i);

                    // Value
                    var elementExpression = arrayLiteral[i];
                    if (elementExpression == null)
                    {
                        generator.LoadNull();
                    }
                    else
                    {
                        elementExpression.GenerateCode(generator, optimizationInfo);
                        EmitConversion.ToAny(generator, elementExpression.GetResultType(optimizationInfo));
                    }

                    // Store the element value.
                    generator.StoreArrayElement(typeof(object));
                }

                // ArrayConstructor.New(object[])
                generator.Call(ReflectionHelpers.Array_New);
            }
            else if (this.Value is List <KeyValuePair <Expression, Expression> > )
            {
                // This is an object literal.
                var properties = (List <KeyValuePair <Expression, Expression> >) this.Value;

                // We'll generate a prototype and a custom object type for it:
                Library.Prototype proto = CreatedPrototype;

                // Create a new object.
                generator.NewObject(proto.TypeConstructor);

                foreach (var keyValuePair in properties)
                {
                    string     propertyName  = keyValuePair.Key.ToString();
                    Expression propertyValue = keyValuePair.Value;

                    // Duplicate the object ref:
                    generator.Duplicate();

                    // Add a new property to the object.

                    Type valueType = propertyValue.GetResultType(optimizationInfo);

                    // Get the property:
                    Library.PropertyVariable pv = proto.GetProperty(propertyName);

                    // Set it:
                    pv.Set(generator, optimizationInfo, false, valueType, delegate(bool two){
                        if (pv.IsConstant)
                        {
                            // Emit the constant:
                            EmitHelpers.EmitValue(generator, pv.ConstantValue);
                        }
                        else
                        {
                            // Write the value to set now:
                            propertyValue.GenerateCode(generator, optimizationInfo);
                        }

                        // Note: This one always ignores 'two'
                    });
                }
            }
            else
            {
                throw new NotImplementedException("Unknown literal type.");
            }
        }