public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { const string errorMsg = "{0}を符号反転出来ません。"; if (target.Value == null) { var msg = String.Format(errorMsg, ConstantNames.NullText); var ctorInfo = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }); var expr = Expression.Throw(Expression.New(ctorInfo, Expression.Constant(errorMsg)), this.ReturnType); var rest = BindingRestrictions.GetExpressionRestriction(BinderHelper.IsNull(target.Expression)); return(new DynamicMetaObject(expr, rest)); } try { var expr = BinderHelper.Wrap(Expression.Negate(Expression.Convert(target.Expression, target.LimitType)), this.ReturnType); var rest = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); return(new DynamicMetaObject(expr, rest)); } catch (InvalidOperationException) { var msgExpr = ExpressionHelper.BetaReduction <string, object, string>( (format, obj) => String.Format(format, obj), Expression.Constant(errorMsg), target.Expression); var ctorInfo = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }); var expr = Expression.Throw(Expression.New(ctorInfo, msgExpr), this.ReturnType); var rest = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); return(new DynamicMetaObject(expr, rest)); } }
/// <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> /// Map関数を呼び出す。 /// </summary> /// <param name="target">関数</param> /// <param name="arg">リスト</param> /// <param name="errorSuggestion"></param> /// <returns>リスト</returns> public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { Expression expr = null; Expression rest = null; var funcType = typeof(Func <object, object>); if (target.LimitType == funcType) { var funcExpr = BinderHelper.Wrap(target.Expression, funcType); expr = ExpressionHelper.BetaReduction <Func <object, object>, object, object>( (func, lst) => ListLib.Map(func, lst), funcExpr, arg.Expression); rest = Expression.TypeIs(target.Expression, funcType); } funcType = typeof(SuffixFunc <Func <object, object> >); if (target.LimitType == funcType) { expr = ExpressionHelper.BetaReduction <SuffixFunc <Func <object, object> >, object, object>( (sfxFunc, lst) => ListLib.Map(sfxFunc.Func, lst), BinderHelper.Wrap(target.Expression, funcType), arg.Expression); rest = Expression.TypeIs(target.Expression, funcType); } // ----- ----- ----- return ----- ----- ----- if (expr != null && rest != null) { return(new DynamicMetaObject( BinderHelper.Wrap(expr, this.ReturnType), BindingRestrictions.GetExpressionRestriction(rest))); } else { return(ThrowArgumentException( target.LimitType + "を用いて射影(それぞれ)できません。", BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } }
/// <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))); }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject left, DynamicMetaObject right, DynamicMetaObject errorSuggestion) { Expression expr; BindingRestrictions rest; if (left.Value == null) { expr = BinderHelper.Wrap(right.Expression, this.ReturnType); rest = BindingRestrictions.GetExpressionRestriction(BinderHelper.IsNull(left.Expression)); } else if (left.LimitType == typeof(bool)) { expr = BinderHelper.Wrap( Expression.Condition(BinderHelper.Wrap(left.Expression, typeof(bool)), left.Expression, right.Expression), this.ReturnType); rest = BindingRestrictions.GetTypeRestriction(left.Expression, typeof(bool)); } else { expr = BinderHelper.Wrap(left.Expression, this.ReturnType); rest = BindingRestrictions.GetExpressionRestriction( Expression.AndAlso( BinderHelper.IsNotNull(left.Expression), Expression.Not(Expression.TypeIs(left.Expression, typeof(bool))))); } return(new DynamicMetaObject(expr, rest)); }
/// <summary> /// 左辺か右辺のいずれかがnullの場合の比較 /// </summary> private DynamicMetaObject FallbackOnNull(DynamicMetaObject left, DynamicMetaObject right) { bool value = this.Operation == ExpressionType.Equal; Expression restExpr = null; if (left.Value == null && right.Value == null) { restExpr = Expression.And( BinderHelper.IsNull(left.Expression), BinderHelper.IsNull(right.Expression)); } else if (left.Value == null) { value ^= true; restExpr = Expression.AndAlso( BinderHelper.IsNull(left.Expression), BinderHelper.IsNotNull(right.Expression)); } else { value ^= true; restExpr = Expression.AndAlso( BinderHelper.IsNull(right.Expression), BinderHelper.IsNotNull(left.Expression)); } var expr = BinderHelper.Wrap(Expression.Constant(value), this.ReturnType); var rest = BindingRestrictions.GetExpressionRestriction(restExpr); return(new DynamicMetaObject(expr, rest)); }
/// <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 FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { Expression boolExpr; BindingRestrictions rest; if (target.Value == null) { boolExpr = Expression.Constant(true); rest = BindingRestrictions.GetExpressionRestriction(BinderHelper.IsNull(target.Expression)); } else if (target.LimitType == typeof(bool)) { boolExpr = Expression.Not(BinderHelper.Wrap(target.Expression, typeof(bool))); rest = BindingRestrictions.GetTypeRestriction(target.Expression, typeof(bool)); } else { boolExpr = Expression.Constant(false); rest = BindingRestrictions.GetExpressionRestriction( Expression.AndAlso( BinderHelper.IsNotNull(target.Expression), Expression.Not(Expression.TypeIs(target.Expression, typeof(bool))))); } var expr = BinderHelper.Wrap(boolExpr, this.ReturnType); return(new DynamicMetaObject(expr, rest)); }
/// <summary> /// 左辺、右辺ともに、nullだった場合 /// </summary> private DynamicMetaObject CompareBotheNull(DynamicMetaObject left, DynamicMetaObject right) { Contract.Requires <ArgumentException>(left.Value == null); Contract.Requires <ArgumentException>(right.Value == null); Expression value = null; switch (this.Operation) { case ExpressionType.LessThan: case ExpressionType.GreaterThan: value = Expression.Constant(false); break; case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThanOrEqual: value = Expression.Constant(true); break; } var expr = BinderHelper.Wrap(value, this.ReturnType); var rest = BindingRestrictions.GetExpressionRestriction( Expression.And( BinderHelper.IsNull(left.Expression), BinderHelper.IsNull(right.Expression))); 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)); } }
private DynamicMetaObject MakeDynamicMetaObject(DynamicMetaObject target, PropertyInfo propInfo) { var targetExpr = BinderHelper.Wrap(target.Expression, target.LimitType); var propAccess = Expression.Property(targetExpr, propInfo); var expr = BinderHelper.Wrap(propAccess, this.ReturnType); var rest = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); return(new DynamicMetaObject(expr, rest)); }
private Expression[] ConvertArguments(DynamicMetaObject[] args, Type[] typeArgs) { var argsExpr = new Expression[args.Length]; for (int i = 0; i < argsExpr.Length; i++) { argsExpr[i] = BinderHelper.Wrap(args[i].Expression, typeArgs[i]); } return(argsExpr); }
private DynamicMetaObject InvokeDelegate(DynamicMetaObject target, DynamicMetaObject[] args) { var funcType = target.LimitType; var typeArgs = funcType.GetGenericArguments(); Type type = null; if (Expression.TryGetFuncType(typeArgs, out type)) { Expression[] argExprs = null; if (typeArgs.Length == args.Length + 1) { argExprs = ConvertArguments(args, typeArgs); } else if (typeArgs.Length == (2 + 1) && args.Length == 1) { // try inline tuple if (args[0].LimitType == typeof(Tuple <object, object>)) { var tupleExpr = BinderHelper.Wrap(args[0].Expression, typeof(Tuple <object, object>)); var fst = ExpressionHelper.BetaReduction <Tuple <object, object>, object>(t => t.Item1, tupleExpr); var snd = ExpressionHelper.BetaReduction <Tuple <object, object>, object>(t => t.Item2, tupleExpr); argExprs = new Expression[] { BinderHelper.Wrap(fst, typeArgs[0]), BinderHelper.Wrap(snd, typeArgs[1]) }; } } if (argExprs != null) { return(new DynamicMetaObject( Expression.Invoke(Expression.Convert(target.Expression, target.LimitType), argExprs), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } } if (Expression.TryGetActionType(typeArgs, out type)) { if (typeArgs.Length == args.Length) { return(new DynamicMetaObject( Expression.Block( Expression.Invoke( Expression.Convert(target.Expression, target.LimitType), ConvertArguments(args, typeArgs)), Expression.Constant(null)), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } } return(ThrowArgumentException( "引数の数が一致していません。", BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); }
/// <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)); }
public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { if (target.Value == null) { return(new DynamicMetaObject( BinderHelper.Wrap(Expression.Constant(true), this.ReturnType), BindingRestrictions.GetExpressionRestriction(BinderHelper.IsNull(target.Expression)))); } if (target.LimitType == typeof(bool)) { return(new DynamicMetaObject( BinderHelper.Wrap(Expression.Not(target.Expression), this.ReturnType), BindingRestrictions.GetTypeRestriction(target.Expression, typeof(bool)))); } return(new DynamicMetaObject( BinderHelper.Wrap(Expression.Constant(false), this.ReturnType), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); }
/// <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)); }
/// <summary> /// 左辺、右辺のいずれかがnullで、もう一方はそうでない場合 /// </summary> private DynamicMetaObject CompareEatherNull(DynamicMetaObject left, DynamicMetaObject right) { Contract.Requires <ArgumentException>( left.Value == null && right.Value != null || left.Value != null && right.Value == null); bool?value = null; switch (this.Operation) { case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: value = false; break; case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: value = true; break; } Expression rest; bool order; if (left.Value == null) { rest = Expression.AndAlso( BinderHelper.IsNull(left.Expression), BinderHelper.IsNotNull(right.Expression)); order = true; } else { rest = Expression.AndAlso( BinderHelper.IsNull(right.Expression), BinderHelper.IsNotNull(left.Expression)); order = false; } var expr = BinderHelper.Wrap(Expression.Constant(value ^ order), this.ReturnType); return(new DynamicMetaObject(expr, BindingRestrictions.GetExpressionRestriction(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)); } }