public PrefixOperation(Operator op, Operand operand) { _target = operand; _baseOp = new OverloadableOperation(op, operand); }
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; }