Exemple #1
0
 public PrefixOperation(Operator op, Operand operand)
 {
     _target = operand;
     _baseOp = new OverloadableOperation(op, operand);
 }
Exemple #2
0
 public PostfixOperation(Operator op, Operand operand)
 {
     this.target = operand;
     baseOp      = new OverloadableOperation(op, operand);
 }
        public PostfixOperation(Operator op, Operand operand)
		{
			_target = operand;
			_baseOp = new OverloadableOperation(op, operand);
		}
		public PrefixOperation(Operator op, Operand operand)
		{
			this.target = operand;
			baseOp = new OverloadableOperation(op, operand);
		}
        void PrepareAf(ITypeMapper typeMapper)
        {
            if (_af != null || !ReferenceEquals(_afInterceptor, null))
            {
                return;
            }
            Operand[] operandsValueOrDefault = new Operand[2];
            Operand[] operandsHasValue       = new Operand[2];
            Operand[] operandsValue          = new Operand[2];
            int       nullables         = 0;
            int       nulls             = 0;
            int       lastNullableIndex = -1;

            for (int i = 0; i < _operands.Length; i++)
            {
                var op = _operands[i];
                if (ReferenceEquals(op, null))
                {
                    nulls++;
                    continue;
                }

                Type vt = op.GetReturnType(typeMapper);
                if (vt.IsValueType && (Helpers.GetNullableUnderlyingType(vt) != null))
                {
                    if (!op.TrivialAccess)
                    {
                        var cache = new LocalCache(op);
                        _caches.Add(cache);
                        op = cache;
                    }
                    operandsValueOrDefault[i] = op.Invoke("GetValueOrDefault", typeMapper).SetNotLeaked();
                    operandsValue[i]          = op.Property("Value", typeMapper).SetNotLeaked();
                    operandsHasValue[i]       = op.Property("HasValue", typeMapper).SetNotLeaked();
                    nullables++;
                    lastNullableIndex = i;
                }
                else
                {
                    operandsValueOrDefault[i] = op;
                    operandsValue[i]          = op;
                }
            }

            if (nullables > 0 && nulls == 0)
            {
                if (_operands.Length == 2)
                {
                    var nonNullableOperation = new OverloadableOperation(_op, operandsValueOrDefault[0], operandsValueOrDefault[1]);

                    Type returnType = nonNullableOperation.GetReturnType(typeMapper);

                    // when no value
                    // for comparsion we return false,
                    // for +-, etc we return nullable null
                    Type nullableReturnType = typeMapper.MapType(typeof(Nullable <>)).MakeGenericType(returnType);


                    // bool? || bool? - not allowed
                    // bool? || bool - not allowed
                    // but bool? | bool  - allowed but not logical!
                    // the difference between logical == != vs normal: for we should always return true or false
                    // expression "(int?) == 5" is not nullable but "int? + 5" is!
                    if (_op.IsLogical)
                    {
                        // true or false required
                        _returnType = typeMapper.MapType(typeof(bool));

                        if (_op.BranchOp == BranchInstruction.Ne)
                        {
                            if (nullables == 1)
                            {
                                Operand notHasValue = !operandsHasValue[lastNullableIndex];
                                _afInterceptor = new Conditional(nonNullableOperation, true, notHasValue);
                            }
                            else
                            {
                                //  ((nullable.GetValueOrDefault() != nullable2.GetValueOrDefault()) ? true : (nullable.HasValue != nullable2.HasValue))
                                Operand hasValueNotEqual = operandsHasValue[0] != operandsHasValue[1];
                                _afInterceptor = new Conditional(nonNullableOperation, true, hasValueNotEqual);
                            }
                        }
                        else
                        {
                            //  ((nullable.GetValueOrDefault() == nullable2.GetValueOrDefault()) ? (nullable.HasValue == nullable2.HasValue) : false)
                            Operand hasValueEqualCheck =
                                nullables == 2
                                        ? operandsHasValue[0] == operandsHasValue[1]
                                        : operandsHasValue[lastNullableIndex];

                            _afInterceptor = new Conditional(nonNullableOperation, hasValueEqualCheck, false);
                        }
                    }
                    else
                    {
                        // nullable return:
                        // long? = int? + long?
                        // long? = (a.HasValue && b.HasValue) ? new long?(a.Value + b.Value) : (long?)null
                        _returnType          = nullableReturnType;
                        nonNullableOperation = new OverloadableOperation(_op, operandsValue[0], operandsValue[1]);
                        var     ctorArgs = new Operand[] { nonNullableOperation };
                        var     ctor     = typeMapper.TypeInfo.FindConstructor(nullableReturnType, ctorArgs);
                        Operand bothWithValueCondition =
                            nullables == 2
                                    ? operandsHasValue[0] && operandsHasValue[1]
                                    : operandsHasValue[lastNullableIndex];

                        _afInterceptor = new Conditional(bothWithValueCondition, new NewObject(ctor, ctorArgs), new DefaultValue(nullableReturnType));
                    }
                    return;
                }
                else if (_operands.Length == 1)
                {
                    // convert increment/decrement to binary operators
                    if (_op.OpCode == OpCodes.Add)
                    {
                        _afInterceptor = _operands[0] + 1;
                        _returnType    = _afInterceptor.GetReturnType(typeMapper);
                        return;
                    }
                    if (_op.OpCode == OpCodes.Sub)
                    {
                        _afInterceptor = _operands[0] - 1;
                        _returnType    = _afInterceptor.GetReturnType(typeMapper);
                        return;
                    }
                }
            }

            PrepareAfNormally(typeMapper, _operands);

            if (_af == null)
            {
                throw new AmbiguousMatchException(Properties.Messages.ErrAmbiguousBinding);
            }

            _returnType = _af.Method.ReturnType;
        }