public override bool CanConvertFrom(Type fromType, Type toType, bool toNotNullable, NarrowingLevel level) { var nonNullable = Binders.GetNonNullableType(toType); return(toType.IsAssignableFrom(fromType) || fromType == typeof(Builtins.Void) || toType == typeof(object) || toType == typeof(string) || nonNullable == typeof(bool) || Binders.IsNumber(nonNullable) && (Binders.IsNumber(fromType) || fromType == typeof(string))); }
public override DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { var t = target.Value as Type; if (t == null) { var tt = target.Value as TypeTracker; if (tt != null) { t = tt.Type; } } if (t != null) { return(Context.Binder.CallMethod( new TjsOverloadResolver(Context.Binder, args, Binders.GetCallSignatureForCallInfo(CallInfo), Microsoft.Scripting.Runtime.CallTypes.None), Microsoft.Scripting.Generation.CompilerHelpers.GetConstructors(t, false), target.Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value)) )); } return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new NotImplementedException()), typeof(object)), target.Restrictions.Merge(BindingRestrictions.Combine(args)))); }
public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { var arg = Expression.Convert(target.Expression, target.LimitType); var restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target); Expression res = null; switch (Operation) { case ExpressionType.Decrement: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Decrement(_context.Convert(arg, typeof(double))); } else { res = Expression.Decrement(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Increment: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Increment(_context.Convert(arg, typeof(double))); } else { res = Expression.Increment(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Negate: if (Binders.IsFloatingPoint(target.LimitType)) { res = Expression.Negate(_context.Convert(arg, typeof(double))); } else { res = Expression.Negate(_context.Convert(arg, typeof(long))); } break; case ExpressionType.Not: res = Expression.Condition(_context.Convert(arg, typeof(bool)), Expression.Constant(0L), Expression.Constant(1L)); break; case ExpressionType.OnesComplement: res = Expression.OnesComplement(_context.Convert(arg, typeof(long))); break; case ExpressionType.UnaryPlus: if (Binders.IsFloatingPoint(target.LimitType)) { res = _context.Convert(arg, typeof(double)); } else if (Binders.IsInteger(target.LimitType)) { res = _context.Convert(arg, typeof(long)); } else if (target.LimitType == typeof(string)) { res = Expression.Call(new Func <string, object>(Binders.ConvertNumber).Method, arg); } break; } if (res != null) { if (res.Type != typeof(object)) { return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions)); } else { return(new DynamicMetaObject(res, restrictions)); } } else { return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な単項演算です。")), typeof(object)), restrictions)); } }
internal static Expression TryConvertExpression(Expression expression, Type toType, ParameterExpression succeeded) { var nonNullable = Binders.GetNonNullableType(toType); if (toType == typeof(object)) { return(InSuccess(Expression.Convert(expression, toType), succeeded)); } else if (toType == expression.Type) { return(InSuccess(expression, succeeded)); } else if (expression.Type == typeof(Builtins.Void)) { if (toType == typeof(string)) { return(InSuccess(Expression.Constant(string.Empty), succeeded)); } else { return(InSuccess(Expression.Default(toType), succeeded)); } } else if (Binders.IsNumber(nonNullable)) { if (Binders.IsNumber(expression.Type)) { return(InSuccess(NewNullableOrThrough(Expression.Convert(expression, nonNullable), toType, nonNullable), succeeded)); } else if (expression.Type == typeof(string)) { ParameterExpression v; Expression test; if (Binders.IsInteger(nonNullable)) { v = Expression.Variable(typeof(long)); test = Expression.Call(typeof(Binders).GetMethod("TryConvertInt64"), expression, v); } else if (Binders.IsFloatingPoint(nonNullable)) { v = Expression.Variable(typeof(double)); test = Expression.Call(typeof(Binders).GetMethod("TryConvertDouble"), expression, v); } else { v = Expression.Variable(nonNullable); test = Expression.Call(nonNullable.GetMethod("TryParse", new[] { typeof(string), nonNullable.MakeByRefType() }), expression, v); } if (succeeded != null) { test = Expression.Assign(succeeded, test); } return(Expression.Block(new[] { v }, Expression.Condition(test, NewNullableOrThrough(v, toType, nonNullable), Expression.Default(toType) ) )); } } else if (toType == typeof(string)) { if (expression.Type.IsValueType) { return(InSuccess(Expression.Call(expression, expression.Type.GetMethod("ToString", Type.EmptyTypes)), succeeded)); } var v = Expression.Variable(expression.Type); return(InSuccess(Expression.Block(new[] { v }, Expression.Condition(Expression.NotEqual(Expression.Assign(v, expression), Expression.Constant(null)), Expression.Call(v, expression.Type.GetMethod("ToString", Type.EmptyTypes)), Expression.Constant("null") ) ), succeeded)); } else if (nonNullable == typeof(bool)) { Expression exp; if (Binders.IsNumber(expression.Type)) { exp = Expression.NotEqual(expression, Expression.Default(expression.Type)); } else if (expression.Type == typeof(string)) { var v = Expression.Variable(typeof(long)); exp = Expression.Block(new[] { v }, Expression.AndAlso( Expression.Call(typeof(long).GetMethod("TryParse", new[] { typeof(string), typeof(long).MakeByRefType() }), expression, v), Expression.NotEqual(v, Expression.Constant(0L)) ) ); } else if (!expression.Type.IsValueType) { exp = Expression.NotEqual(expression, Expression.Constant(null)); } else if (expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(Nullable <>)) { exp = Expression.Property(expression, "HasValue"); } else { return(InSuccess(nonNullable == toType ? Expression.Constant(true) : Expression.Constant(new bool?(true)), succeeded)); } return(InSuccess(NewNullableOrThrough(exp, toType, nonNullable), succeeded)); } return(null); }
internal static object ConvertInternal(object obj, Type toType) { Type fromType; if (obj == null || (fromType = obj.GetType()) == typeof(Builtins.Void)) { if (toType == typeof(string)) { return(obj == null ? "null" : string.Empty); } else { return(toType.IsValueType ? toType.GetConstructor(Type.EmptyTypes).Invoke(null) : null); } } if (toType == typeof(object) || toType == fromType) { return(obj); } if (toType == typeof(string)) { return(obj.ToString()); } var nonNullableTo = Binders.GetNonNullableType(toType); if (Binders.IsNumber(nonNullableTo)) { if (Binders.IsNumber(fromType)) { var converted = System.Convert.ChangeType(obj, nonNullableTo); if (nonNullableTo == toType) { return(converted); } else { return(Activator.CreateInstance(toType, converted)); } } else if (fromType == typeof(string)) { var tryParse = nonNullableTo.GetMethod("TryParse", new[] { typeof(string), nonNullableTo.MakeByRefType() }); var argument = new[] { obj, null }; if ((bool)tryParse.Invoke(null, argument)) { if (nonNullableTo == toType) { return(argument[1]); } else { return(Activator.CreateInstance(toType, argument[1])); } } else { return(Activator.CreateInstance(toType)); } } } else if (nonNullableTo == typeof(bool)) { object converted; if (Binders.IsNumber(fromType)) { converted = System.Convert.ChangeType(obj, nonNullableTo); } else if (fromType == typeof(string)) { long value; converted = long.TryParse((string)obj, out value) && value != 0; } else if (!fromType.IsValueType) { converted = obj != null; } else if (fromType.IsGenericType && fromType.GetGenericTypeDefinition() == typeof(Nullable <>)) { converted = fromType.GetProperty("HasValue").GetValue(obj); } else { converted = true; } if (nonNullableTo == toType) { return(converted); } else { return(new bool?((bool)converted)); } } return(NoValue); }
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { var left = Expression.Convert(target.Expression, target.LimitType); var right = Expression.Convert(arg.Expression, arg.LimitType); Expression res = null; switch (Operation) { case ExpressionType.Add: if (target.LimitType == typeof(string) || arg.LimitType == typeof(string)) { res = Expression.Call(new Func <string, string, string>(string.Concat).Method, _context.Convert(left, typeof(string)), _context.Convert(right, typeof(string))); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Add(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Add(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; case ExpressionType.And: res = Expression.And(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.Divide: res = Expression.Divide(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); break; case ExpressionType.Equal: res = Expression.Condition(Equal(left, right), Expression.Constant(1L), Expression.Constant(0L)); break; case ExpressionType.ExclusiveOr: res = Expression.ExclusiveOr(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.GreaterThan: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.GreaterThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.GreaterThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.GreaterThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.GreaterThanOrEqual: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.GreaterThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.GreaterThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.LeftShift: res = Expression.LeftShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int))); break; case ExpressionType.LessThan: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.LessThan(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.LessThan(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.LessThan(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.LessThanOrEqual: { Expression exp; if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { exp = Expression.LessThanOrEqual(Expression.Call(new Func <string, string, int>(string.CompareOrdinal).Method, left, right), Expression.Constant(0)); } else if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { exp = Expression.LessThanOrEqual(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } res = Expression.Condition(exp, Expression.Constant(1L), Expression.Constant(0L)); } break; case ExpressionType.Modulo: res = Expression.Modulo(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.Multiply: if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Multiply(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Multiply(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; case ExpressionType.NotEqual: res = Expression.Condition(Equal(left, right), Expression.Constant(0L), Expression.Constant(1L)); break; case ExpressionType.Or: res = Expression.Or(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); break; case ExpressionType.RightShift: res = Expression.RightShift(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(int))); break; case ExpressionType.Subtract: if (Binders.IsFloatingPoint(target.LimitType) || Binders.IsFloatingPoint(arg.LimitType)) { res = Expression.Subtract(_context.Convert(left, typeof(double)), _context.Convert(right, typeof(double))); } else { res = Expression.Subtract(_context.Convert(left, typeof(long)), _context.Convert(right, typeof(long))); } break; } var restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg)); if (res != null) { return(new DynamicMetaObject(Expression.Convert(res, typeof(object)), restrictions)); } else { return(errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("不正な二項演算です。")), typeof(object)), restrictions)); } }
public DynamicMetaObject FallbackOperation(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { Expression convertedTarget = Expression.Convert(target.Expression, target.LimitType); Expression[] convertedArgs = args.Select(x => Expression.Convert(x.Expression, x.LimitType)).ToArray(); Expression exp = null; var restrictions = target.Restrictions.Merge(GetTypeRestriction(target)); int usedArgs = 0; switch (OperationKind) { // Unary case TjsOperationKind.CharCodeToChar: exp = Expression.Call(Context.Convert(convertedTarget, typeof(char)), "ToString", null); break; case TjsOperationKind.CharToCharCode: exp = Expression.Call(new Func <string, long>(TjsOperationHelper.CharToCharCode).Method, Context.Convert(convertedTarget, typeof(string))); break; case TjsOperationKind.Evaluate: case TjsOperationKind.Invalidate: case TjsOperationKind.IsValid: //MARK: not implemented? if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new NotImplementedException())), BindingRestrictions.Empty); } break; case TjsOperationKind.TypeOf: if (target.RuntimeType == null) { exp = Expression.Constant("Object"); } else if (target.RuntimeType == typeof(Builtins.Void)) { exp = Expression.Constant("void"); } else if (target.RuntimeType == typeof(string)) { exp = Expression.Constant("String"); } else if (Binders.IsInteger(target.RuntimeType)) { exp = Expression.Constant("Integer"); } else if (Binders.IsFloatingPoint(target.RuntimeType)) { exp = Expression.Constant("Real"); } else { exp = Expression.Constant("Object"); } break; // Unary (Special) case TjsOperationKind.InvokePropertyHandler: if (target.LimitType == typeof(Property)) { if (args.Length == 0) { exp = Expression.Property(convertedTarget, (System.Reflection.PropertyInfo)Utils.GetMember <Property>(x => x.Value)); } else if (args.Length == 1) { exp = Expression.Assign(Expression.Property(convertedTarget, (System.Reflection.PropertyInfo)Utils.GetMember <Property>(x => x.Value)), args[0].Expression); usedArgs = 1; } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("引数の数が * 演算子に適用できる許容範囲を超えています。"))), BindingRestrictions.Empty); } } } else if (target.LimitType == typeof(BoundMemberTracker)) { var tracker = (BoundMemberTracker)target.Value; if (tracker.Instance == null) { tracker = new BoundMemberTracker(tracker.BoundTo, new DynamicMetaObject(Expression.Constant(tracker.ObjectInstance), BindingRestrictions.Empty, tracker.ObjectInstance)); } var type = tracker.Instance.GetLimitType(); if (args.Length == 0) { var res = tracker.GetValue(new TjsOverloadResolverFactory(Context.Binder), Context.Binder, type); if (res != null) { exp = res.Expression; restrictions = restrictions.Merge(res.Restrictions); } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("メンバの取得に失敗しました。"))), BindingRestrictions.Empty); } } } else if (args.Length == 1) { var res = tracker.SetValue(new TjsOverloadResolverFactory(Context.Binder), Context.Binder, type, args[0]); if (res != null) { exp = res.Expression; restrictions = restrictions.Merge(res.Restrictions); usedArgs = 1; } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("メンバの設定に失敗しました。"))), BindingRestrictions.Empty); } } } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("引数の数が * 演算子に適用できる許容範囲を超えています。"))), BindingRestrictions.Empty); } } } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("プロパティ以外に対して * 演算子が使用されました。"))), BindingRestrictions.Empty); } } break; // Binary (Arithmetic & Logical) case TjsOperationKind.FloorDivide: exp = Expression.Divide(Context.Convert(convertedTarget, typeof(long)), Context.Convert(convertedArgs[0], typeof(long))); usedArgs = 1; break; case TjsOperationKind.RightShiftLogical: exp = Expression.Convert(Expression.RightShift(Context.Convert(convertedTarget, typeof(ulong)), Context.Convert(convertedArgs[0], typeof(int))), typeof(long)); usedArgs = 1; break; // Binary (Comparison) case TjsOperationKind.DistinctEqual: if (convertedTarget.Type == convertedArgs[0].Type) { exp = Expression.Condition(Expression.Equal(convertedTarget, convertedArgs[0]), Expression.Constant(1L), Expression.Constant(0L)); } else { exp = Expression.Constant(0L); } usedArgs = 1; break; case TjsOperationKind.DistinctNotEqual: if (convertedTarget.Type == convertedArgs[0].Type) { exp = Expression.Condition(Expression.Equal(convertedTarget, convertedArgs[0]), Expression.Constant(0L), Expression.Constant(1L)); } else { exp = Expression.Constant(1L); } usedArgs = 1; break; // Binary (Special) case TjsOperationKind.InstanceOf: exp = Expression.Condition(Expression.Equal(Expression.Constant(convertedTarget.Type.Name), Context.Convert(convertedArgs[0], typeof(string))), Expression.Constant(1L), Expression.Constant(0L) ); usedArgs = 1; break; case TjsOperationKind.InContextOf: if (target.Value is IContextChangeable) { exp = Expression.Call(Expression.Convert(convertedTarget, typeof(IContextChangeable)), "ChangeContext", null, args[0].Expression); } else if (target.LimitType == typeof(BoundMemberTracker)) { exp = Expression.New((System.Reflection.ConstructorInfo)Utils.GetMember(() => new BoundMemberTracker(null, (object)null)), Expression.PropertyOrField(convertedTarget, "BoundTo"), args[0].Expression); } else { if (errorSuggestion == null) { errorSuggestion = new DynamicMetaObject(Expression.Throw(Expression.Constant(new InvalidOperationException("incontextof 演算子は指定されたオブジェクトに適用できません。"))), BindingRestrictions.Empty); } } usedArgs = 1; break; } for (int i = 0; i < usedArgs; i++) { restrictions = restrictions.Merge(args[i].Restrictions).Merge(GetTypeRestriction(args[i])); } if (exp == null) { return(new DynamicMetaObject(errorSuggestion.Expression, errorSuggestion.Restrictions.Merge(restrictions))); } if (exp.Type != typeof(object)) { exp = Expression.Convert(exp, typeof(object)); } return(new DynamicMetaObject(exp, restrictions)); }
public TjsInvokeBinder(TjsContext context, CallSignature signature) : base(Binders.GetCallInfoForCallSignature(signature)) { _context = context; Signature = signature; }