/// <summary> /// 暗黙のキャストを探す。 /// </summary> private DynamicMetaObject DefferentType(DynamicMetaObject left, DynamicMetaObject right) { var val = TryCalcNumeric(left, right); if (val != null) { return(val); } // 左辺のキャスト var mInfo = BinderHelper.GetImplicitCast(left.LimitType, right.LimitType); if (mInfo != null) { Expression expr = Expression.MakeBinary(this.Operation, BinderHelper.Wrap(left.Expression, left.LimitType, right.LimitType), Expression.Convert(right.Expression, right.LimitType)); return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BinderHelper.GetTypeRestriction(left, right))); } // 右辺のキャスト mInfo = BinderHelper.GetImplicitCast(right.LimitType, left.LimitType); if (mInfo != null) { Expression expr = Expression.MakeBinary(this.Operation, Expression.Convert(left.Expression, left.LimitType), BinderHelper.Wrap(right.Expression, right.LimitType, left.LimitType)); return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BinderHelper.GetTypeRestriction(left, right))); } return(BinderHelper.NoResult(_name, this.ReturnType, left, right)); }
/// <summary> /// 整数と小数の比較 /// </summary> private DynamicMetaObject TryCalcOnDefferentNumericType(DynamicMetaObject left, DynamicMetaObject right) { Expression leftExpr = BinderHelper.LimitTypeConvert(left); Expression rightExpr = BinderHelper.LimitTypeConvert(right); Expression expr = null; foreach (var pattern in BinderHelper.CastPatterns) { if (leftExpr.Type == pattern.Narrow && rightExpr.Type == pattern.Wide) { var upperLeft = Expression.Convert(leftExpr, pattern.Wide); expr = Expression.MakeBinary(this.Operation, upperLeft, rightExpr); break; } if (leftExpr.Type == pattern.Wide && rightExpr.Type == pattern.Narrow) { var upperRight = Expression.Convert(rightExpr, pattern.Wide); expr = Expression.MakeBinary(this.Operation, leftExpr, upperRight); break; } } if (expr == null) { return(null); } return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BinderHelper.GetTypeRestriction(left, right))); }
/// <summary> /// 暗黙の型変換が存在する場合,それを利用する。 /// </summary> private DynamicMetaObject TryImplicitCast(DynamicMetaObject left, DynamicMetaObject right) { Expression cmpExpr = null; if (BinderHelper.GetImplicitCast(left.LimitType, right.LimitType) != null) { try { cmpExpr = Expression.MakeBinary(this.Operation, BinderHelper.Wrap(left.Expression, left.LimitType, right.LimitType), BinderHelper.Wrap(right.Expression, right.LimitType)); } catch (InvalidCastException) { } } if (BinderHelper.GetImplicitCast(right.LimitType, left.LimitType) != null) { try { cmpExpr = Expression.MakeBinary(this.Operation, BinderHelper.Wrap(left.Expression, left.LimitType), BinderHelper.Wrap(right.Expression, right.LimitType, left.LimitType)); } catch (InvalidCastException) { } } if (cmpExpr == null) { return(null); } var expr = BinderHelper.Wrap(cmpExpr, this.ReturnType); var rest = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, rest)); }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { if (target.Value == null || arg.Value == null) { return(BinderHelper.NullErrorOnOperation(_name, this.ReturnType, target, arg)); } try { if (target.LimitType == arg.LimitType) { var type = target.LimitType; var leftExpr = BinderHelper.Wrap(target.Expression, type); var rightExpr = BinderHelper.Wrap(arg.Expression, type); var checkedExpr = OverflowCheckingCalc(leftExpr, rightExpr); if (checkedExpr != null) { var bindings = BinderHelper.GetTypeRestriction(target, arg); return(new DynamicMetaObject(checkedExpr, bindings)); } } Expression expr = Expression.MakeBinary( this.Operation, BinderHelper.Wrap(target.Expression, target.LimitType), BinderHelper.Wrap(arg.Expression, arg.LimitType)); return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BinderHelper.GetTypeRestriction(target, arg))); } catch (InvalidOperationException) { return(DefferentType(target, arg)); } }
/// <summary> /// 整数と小数の演算を行う /// </summary> private DynamicMetaObject TryCalcNumeric(DynamicMetaObject left, DynamicMetaObject right) { Expression leftExpr = BinderHelper.LimitTypeConvert(left); Expression rightExpr = BinderHelper.LimitTypeConvert(right); Expression expr = null; foreach (var pattern in BinderHelper.CastPatterns) { if (leftExpr.Type == pattern.Narrow && rightExpr.Type == pattern.Wide) { var upperLeft = Expression.Convert(leftExpr, pattern.Wide); expr = OverflowCheckingCalc(upperLeft, rightExpr); break; } if (leftExpr.Type == pattern.Wide && rightExpr.Type == pattern.Narrow) { var upperRight = Expression.Convert(rightExpr, pattern.Wide); expr = OverflowCheckingCalc(leftExpr, upperRight); break; } } if (expr == null) { return(null); } var bindings = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, bindings)); }
/// <summary> /// 適切な計算方法が見つからなかった場合、RuntimeBinderExceptionを投げる。 /// </summary> public static DynamicMetaObject NoResult(string name, Type type, DynamicMetaObject left, DynamicMetaObject right) { var ctorInfo = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }); var errorMsg = "{0}と{1}を" + name + "出来ません。"; var mInfo = typeof(String).GetMethod("Format", new[] { typeof(string), typeof(object), typeof(object) }); var msgExpr = Expression.Call(mInfo, Expression.Constant(errorMsg), Expression.Convert(left.Expression, typeof(object)), Expression.Convert(right.Expression, typeof(object))); var expr = Expression.Throw(Expression.New(ctorInfo, msgExpr), typeof(object)); return(new DynamicMetaObject(expr, BinderHelper.GetTypeRestriction(left, right))); }
/// <summary> /// 左辺と右辺を参照比較する。 /// </summary> private DynamicMetaObject TryReferenceEqual(DynamicMetaObject left, DynamicMetaObject right) { if (left.LimitType.IsValueType || right.LimitType.IsValueType) { return(null); } var boolResult = Expression.Constant(this.Operation == ExpressionType.Equal); Expression expr = ExpressionHelper.BetaReduction( (object objA, object objB, bool result) => (object)(Object.ReferenceEquals(objA, objB) == result), left.Expression, right.Expression, boolResult); expr = BinderHelper.Wrap(expr, this.ReturnType); var rest = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, rest)); }
/// <summary> /// 標準の比較を用いる。 /// 失敗した場合,右辺と左辺は等しくないものとする。 /// </summary> private DynamicMetaObject Default(DynamicMetaObject left, DynamicMetaObject right) { Expression eqExpr = null; try { eqExpr = Expression.MakeBinary(this.Operation, BinderHelper.Wrap(left.Expression, left.LimitType), BinderHelper.Wrap(right.Expression, right.LimitType)); } catch (InvalidOperationException) { eqExpr = Expression.Constant(this.Operation != ExpressionType.Equal); } var expr = BinderHelper.Wrap(eqExpr, this.ReturnType); var rest = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, rest)); }
/// <summary> /// 左辺がIComparable<T>を実装している場合、CompareToメソッドを呼ぶことで比較する。 /// </summary> private DynamicMetaObject TryUseIComparableT(DynamicMetaObject left, DynamicMetaObject right) { var types = left.LimitType.GetInterfaces(); var cmpType = typeof(IComparable <>).MakeGenericType(right.LimitType); var hasGeneric = Array.IndexOf(types, cmpType) != -1; if (hasGeneric == false) { return(null); } var callExpr = Expression.Call( Expression.Convert(left.Expression, cmpType), cmpType.GetMethod("CompareTo", new[] { right.LimitType }), Expression.Convert(right.Expression, right.LimitType)); var expr = BinderHelper.Wrap(ExpressionHelper.BetaReduction(_compareExpr, callExpr), this.ReturnType); var rest = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, rest)); }
/// <summary> /// 左辺がIEquatable<T>を継承している場合,それを利用する。 /// </summary> private DynamicMetaObject TryUseIEquatableT(DynamicMetaObject left, DynamicMetaObject right) { var types = left.LimitType.GetInterfaces(); var cmpType = typeof(IEquatable <>).MakeGenericType(right.LimitType); var hasGeneric = Array.IndexOf(types, cmpType) != -1; if (hasGeneric == false) { return(null); } var callExpr = Expression.Call( Expression.Convert(left.Expression, cmpType), cmpType.GetMethod("Equals", new[] { right.LimitType }), Expression.Convert(right.Expression, right.LimitType)); var result = Expression.Constant(this.Operation == ExpressionType.Equal); var expr = BinderHelper.Wrap(Expression.Equal(callExpr, result), this.ReturnType); var rest = BinderHelper.GetTypeRestriction(left, right); return(new DynamicMetaObject(expr, rest)); }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { if (target.Value == null && arg.Value == null) { return(CompareBotheNull(target, arg)); } if (target.Value == null || arg.Value == null) { return(CompareEatherNull(target, arg)); } try { var expr = Expression.MakeBinary( this.Operation, BinderHelper.Wrap(target.Expression, target.LimitType), BinderHelper.Wrap(arg.Expression, arg.LimitType)); return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BinderHelper.GetTypeRestriction(target, arg))); } catch (InvalidOperationException) { return(Search(target, arg)); } }