private MetaObject MakeMetaMethodCall(CallSignature signature, ParameterBinder parameterBinder, TargetInfo targetInfo) { Restrictions restrictions = Restrictions.Combine(targetInfo.Arguments).Merge(targetInfo.Restrictions); if (targetInfo.Instance != null) { restrictions = targetInfo.Instance.Restrictions.Merge(restrictions); } if (targetInfo.Instance != null) { return(CallInstanceMethod( parameterBinder, targetInfo.Targets, targetInfo.Instance, targetInfo.Arguments, signature, restrictions )); } return(CallMethod( parameterBinder, targetInfo.Targets, targetInfo.Arguments, signature, restrictions)); }
private MetaObject MakeMethodIndexRule(string oper, MetaObject[] args) { MethodInfo[] defaults = GetMethodsFromDefaults(args[0].LimitType.GetDefaultMembers(), oper); if (defaults.Length != 0) { MethodBinder binder = MethodBinder.MakeBinder( this, oper == StandardOperators.GetItem ? "get_Item" : "set_Item", defaults); MetaObject[] selfWithArgs = args; ParameterExpression arg2 = null; if (oper == StandardOperators.SetItem) { Debug.Assert(args.Length >= 2); // need to save arg2 in a temp because it's also our result arg2 = Ast.Variable(args[2].Expression.Type, "arg2Temp"); args[2] = new MetaObject( Ast.Assign(arg2, args[2].Expression), args[2].Restrictions ); } BindingTarget target = binder.MakeBindingTarget(CallTypes.ImplicitInstance, selfWithArgs); Restrictions restrictions = Restrictions.Combine(args); if (target.Success) { if (oper == StandardOperators.GetItem) { return(new MetaObject( target.MakeExpression(), restrictions.Merge(Restrictions.Combine(target.RestrictedArguments)) )); } else { return(new MetaObject( Ast.Block( new ParameterExpression[] { arg2 }, target.MakeExpression(), arg2 ), restrictions.Merge(Restrictions.Combine(target.RestrictedArguments)) )); } } return(MakeError( MakeInvalidParametersError(target), restrictions )); } return(null); }
private MetaObject IndexOperation(MetaObject fallback, MetaObject[] args, string method) { ParameterExpression callable = Expression.Variable(typeof(DispCallable), "callable"); Expression[] callArgs = new Expression[args.Length + 1]; for (int i = 0; i < args.Length; i++) { callArgs[i + 1] = args[i].Expression; } callArgs[0] = callable; Expression result = Expression.Block( new ParameterExpression[] { callable }, Expression.Condition( Expression.Call( Expression.Convert(Expression, typeof(IDispatchComObject)), typeof(IDispatchComObject).GetMethod(method), callable ), Expression.Dynamic(new ComInvokeAction(), typeof(object), callArgs), Helpers.Convert(fallback.Expression, typeof(object)) ) ); return(new MetaObject( result, Restrictions.Combine(args).Merge(IDispatchRestriction()).Merge(fallback.Restrictions) )); }
internal static MetaObject RewriteStrongBoxAsRef(CallSiteBinder action, MetaObject target, MetaObject[] args) { Debug.Assert(action != null && target != null && args != null); var restrictions = target.Restrictions.Merge(Restrictions.Combine(args)); Expression[] argExpressions = new Expression[args.Length + 1]; Type[] signatureTypes = new Type[args.Length + 3]; // args + CallSite, target, returnType signatureTypes[0] = typeof(CallSite); //TODO: we are not restricting on target type here, but in theory we could. //It is a tradeoff between rule reuse and higher polymorphism of the site. argExpressions[0] = target.Expression; signatureTypes[1] = target.Expression.Type; for (int i = 0; i < args.Length; i++) { MetaObject currArgument = args[i]; if (IsStrongBoxArg(currArgument)) { restrictions = restrictions.Merge(Restrictions.GetTypeRestriction(currArgument.Expression, currArgument.LimitType)); // we have restricted this argument to LimitType so we can convert and conversion will be trivial cast. Expression boxedValueAccessor = Expression.Field( Helpers.Convert( currArgument.Expression, currArgument.LimitType ), currArgument.LimitType.GetField("Value") ); argExpressions[i + 1] = boxedValueAccessor; signatureTypes[i + 2] = boxedValueAccessor.Type.MakeByRefType(); } else { argExpressions[i + 1] = currArgument.Expression; signatureTypes[i + 2] = currArgument.Expression.Type; } } // Last signatureType is the return value signatureTypes[signatureTypes.Length - 1] = typeof(object); return(new MetaObject( Expression.MakeDynamic( Expression.GetDelegateType(signatureTypes), action, argExpressions ), restrictions )); }
public override MetaObject BindCreateInstance(CreateInstanceBinder binder, MetaObject[] args) { return(new MetaObject( Expression.Call( AstUtils.Convert(Expression, typeof(ComTypeClassDesc)), typeof(ComTypeClassDesc).GetMethod("CreateInstance") ), Restrictions.Combine(args).Merge( Restrictions.GetTypeRestriction(Expression, typeof(ComTypeClassDesc)) ) )); }
private static MetaObject MakeOperatorError(OperatorInfo info, MetaObject[] args) { return(new MetaObject( Ast.Throw( AstUtils.ComplexCallHelper( typeof(BinderOps).GetMethod("BadArgumentsForOperation"), ArrayUtils.Insert((Expression)Ast.Constant(info.Operator), MetaObject.GetExpressions(args)) ) ), Restrictions.Combine(args) )); }
private static MetaObject MakeInvalidParametersRule(CallTypes callType, CallSignature signature, DefaultBinder binder, IList <MetaObject> args, Restrictions restrictions, BindingTarget bt) { Restrictions restriction = MakeSplatTests(callType, signature, true, args); // restrict to the exact type of all parameters for errors for (int i = 0; i < args.Count; i++) { args[i] = args[i].Restrict(args[i].LimitType); } return(MakeError( binder.MakeInvalidParametersError(bt), restrictions.Merge(Restrictions.Combine(args).Merge(restriction)) )); }
private MetaObject TryMakeBindingTarget(MethodInfo[] targets, MetaObject[] args, Expression codeContext, Restrictions restrictions) { MethodBinder mb = MethodBinder.MakeBinder(this, targets[0].Name, targets); BindingTarget target = mb.MakeBindingTarget(CallTypes.None, args); if (target.Success) { return(new MetaObject( target.MakeExpression(new ParameterBinderWithCodeContext(this, codeContext)), restrictions.Merge(Restrictions.Combine(target.RestrictedArguments)) )); } return(null); }
private MetaObject TryMakeInvertedBindingTarget(MethodBase[] targets, MetaObject[] args) { MethodBinder mb = MethodBinder.MakeBinder(this, targets[0].Name, targets); MetaObject[] selfArgs = args; BindingTarget target = mb.MakeBindingTarget(CallTypes.None, selfArgs); if (target.Success) { return(new MetaObject( Ast.Not(target.MakeExpression()), Restrictions.Combine(target.RestrictedArguments) )); } return(null); }
private MetaObject TryNumericComparison(OperatorInfo info, MetaObject[] args) { MethodInfo[] targets = FilterNonMethods( args[0].LimitType, GetMember(OldDoOperationAction.Make(this, info.Operator), args[0].LimitType, "Compare") ); if (targets.Length > 0) { MethodBinder mb = MethodBinder.MakeBinder(this, targets[0].Name, targets); BindingTarget target = mb.MakeBindingTarget(CallTypes.None, args); if (target.Success) { Expression call = AstUtils.Convert(target.MakeExpression(), typeof(int)); switch (info.Operator) { case Operators.GreaterThan: call = Ast.GreaterThan(call, Ast.Constant(0)); break; case Operators.LessThan: call = Ast.LessThan(call, Ast.Constant(0)); break; case Operators.GreaterThanOrEqual: call = Ast.GreaterThanOrEqual(call, Ast.Constant(0)); break; case Operators.LessThanOrEqual: call = Ast.LessThanOrEqual(call, Ast.Constant(0)); break; case Operators.Equals: call = Ast.Equal(call, Ast.Constant(0)); break; case Operators.NotEquals: call = Ast.NotEqual(call, Ast.Constant(0)); break; case Operators.Compare: break; } return(new MetaObject( call, Restrictions.Combine(target.RestrictedArguments) )); } } return(null); }
internal MetaObject Invoke() { _keywordArgNames = GetArgumentNames(); // will not include implicit instance argument (if any) Type[] explicitArgTypes = _args.Map(a => a.LimitType); Type[] marshalArgTypes = _args.Map(a => MarshalType(a)); Expression[] explicitArgExprs = _args.Map(a => a.Expression); _totalExplicitArgs = explicitArgTypes.Length; _varEnumSelector = new VarEnumSelector(marshalArgTypes); // We already tested the instance, so no need to test it again for (int i = 0; i < explicitArgTypes.Length; i++) { _restrictions = _restrictions.Merge(Restrictions.GetTypeRestriction(explicitArgExprs[i], explicitArgTypes[i])); } return(new MetaObject( CreateScope(MakeIDispatchInvokeTarget()), Restrictions.Combine(_args).Merge(_restrictions) )); }
// TODO: support for IgnoreCase in underlying ScriptScope APIs public override MetaObject BindInvokeMember(InvokeMemberBinder action, MetaObject[] args) { var fallback = action.FallbackInvokeMember(this, args); var result = Expression.Variable(typeof(object), "result"); var fallbackInvoke = action.FallbackInvoke(new MetaObject(result, Restrictions.Empty), args, null); return(new MetaObject( Expression.Block( new ParameterExpression[] { result }, Expression.Condition( Expression.Call( AstUtils.Convert(Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("TryGetVariable", new[] { typeof(string), typeof(object).MakeByRefType() }), Expression.Constant(action.Name), result ), Expression.Convert(fallbackInvoke.Expression, typeof(object)), Expression.Convert(fallback.Expression, typeof(object)) ) ), Restrictions.Combine(args).Merge(Restrictions.GetTypeRestriction(Expression, typeof(ScriptScope))).Merge(fallback.Restrictions) )); }
private MetaObject CallWorker(ParameterBinder parameterBinder, IList <MethodBase> targets, IList <MetaObject> args, CallSignature signature, CallTypes callType, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, string name, out BindingTarget target) { ContractUtils.RequiresNotNull(parameterBinder, "parameterBinder"); ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.RequiresNotNullItems(targets, "targets"); ContractUtils.RequiresNotNull(restrictions, "restrictions"); MetaObject[] finalArgs; SymbolId[] argNames; if (callType == CallTypes.ImplicitInstance) { GetArgumentNamesAndTypes(signature, ArrayUtils.RemoveFirst(args), out argNames, out finalArgs); finalArgs = ArrayUtils.Insert(args[0], finalArgs); } else { GetArgumentNamesAndTypes(signature, args, out argNames, out finalArgs); } // attempt to bind to an individual method MethodBinder binder = MethodBinder.MakeBinder( this, name ?? GetTargetName(targets), targets, argNames, minLevel, maxLevel); target = binder.MakeBindingTarget(callType, finalArgs); if (target.Success) { // if we succeed make the target for the rule return(new MetaObject( target.MakeExpression(parameterBinder), restrictions.Merge(MakeSplatTests(callType, signature, args).Merge(Restrictions.Combine(target.RestrictedArguments))) )); } // make an error rule return(MakeInvalidParametersRule(callType, signature, this, args, restrictions, target)); }
/// <summary> /// Produces a rule for comparing a value to null - supports comparing object references and nullable types. /// </summary> private static MetaObject TryNullComparisonRule(MetaObject[] args) { Type otherType = args[0].LimitType; Restrictions restrictions = Restrictions.GetTypeRestriction(args[0].Expression, args[0].LimitType).Merge(Restrictions.Combine(args)); if (args[0].LimitType == typeof(Null)) { if (!otherType.IsValueType) { return(new MetaObject( Ast.Equal(args[0].Expression, Ast.Constant(null)), restrictions )); } else if (otherType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new MetaObject( Ast.Property(args[0].Expression, otherType.GetProperty("HasValue")), restrictions )); } } else if (otherType == typeof(Null)) { if (!args[0].LimitType.IsValueType) { return(new MetaObject( Ast.Equal(args[0].Expression, Ast.Constant(null)), restrictions )); } else if (args[0].LimitType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(new MetaObject( Ast.Property(args[0].Expression, otherType.GetProperty("HasValue")), restrictions )); } } return(null); }
private static MetaObject TryPrimitiveCompare(OperatorInfo info, MetaObject[] args) { if (TypeUtils.GetNonNullableType(args[0].LimitType) == TypeUtils.GetNonNullableType(args[1].LimitType) && TypeUtils.IsNumeric(args[0].LimitType)) { Expression arg0 = args[0].Expression; Expression arg1 = args[1].Expression; // TODO: Nullable<PrimitveType> Support Expression expr; switch (info.Operator) { case Operators.Equals: expr = Ast.Equal(arg0, arg1); break; case Operators.NotEquals: expr = Ast.NotEqual(arg0, arg1); break; case Operators.GreaterThan: expr = Ast.GreaterThan(arg0, arg1); break; case Operators.LessThan: expr = Ast.LessThan(arg0, arg1); break; case Operators.GreaterThanOrEqual: expr = Ast.GreaterThanOrEqual(arg0, arg1); break; case Operators.LessThanOrEqual: expr = Ast.LessThanOrEqual(arg0, arg1); break; default: throw new InvalidOperationException(); } return(new MetaObject( expr, Restrictions.GetTypeRestriction(arg0, args[0].LimitType).Merge(Restrictions.GetTypeRestriction(arg1, args[0].LimitType)).Merge(Restrictions.Combine(args)) )); } return(null); }
private Restrictions ComTypeLibInfoRestrictions(params MetaObject[] args) { return(Restrictions.Combine(args).Merge(Restrictions.GetTypeRestriction(Expression, typeof(ComTypeLibInfo)))); }
private static MetaObject TryMakeDefaultUnaryRule(OperatorInfo info, Expression codeContext, MetaObject[] args) { if (args.Length == 1) { Restrictions restrictions = Restrictions.GetTypeRestriction(args[0].Expression, args[0].LimitType).Merge(Restrictions.Combine(args)); switch (info.Operator) { case Operators.IsTrue: if (args[0].LimitType == typeof(bool)) { return(args[0]); } break; case Operators.Negate: if (TypeUtils.IsArithmetic(args[0].LimitType)) { return(new MetaObject( Ast.Negate(args[0].Expression), restrictions )); } break; case Operators.Not: if (TypeUtils.IsIntegerOrBool(args[0].LimitType)) { return(new MetaObject( Ast.Not(args[0].Expression), restrictions )); } break; case Operators.Documentation: object[] attrs = args[0].LimitType.GetCustomAttributes(typeof(DocumentationAttribute), true); string documentation = String.Empty; if (attrs.Length > 0) { documentation = ((DocumentationAttribute)attrs[0]).Documentation; } return(new MetaObject( Ast.Constant(documentation), restrictions )); case Operators.MemberNames: if (typeof(IMembersList).IsAssignableFrom(args[0].LimitType)) { return(MakeIMembersListRule(codeContext, args[0])); } MemberInfo[] members = args[0].LimitType.GetMembers(); Dictionary <string, string> mems = new Dictionary <string, string>(); foreach (MemberInfo mi in members) { mems[mi.Name] = mi.Name; } string[] res = new string[mems.Count]; mems.Keys.CopyTo(res, 0); return(new MetaObject( Ast.Constant(res), restrictions )); case Operators.CallSignatures: return(MakeCallSignatureResult(CompilerHelpers.GetMethodTargets(args[0].LimitType), args[0])); case Operators.IsCallable: // IsCallable() is tightly tied to Call actions. So in general, we need the call-action providers to also // provide IsCallable() status. // This is just a rough fallback. We could also attempt to simulate the default CallBinder logic to see // if there are any applicable calls targets, but that would be complex (the callbinder wants the argument list, // which we don't have here), and still not correct. bool callable = false; if (typeof(Delegate).IsAssignableFrom(args[0].LimitType) || typeof(MethodGroup).IsAssignableFrom(args[0].LimitType)) { callable = true; } return(new MetaObject( Ast.Constant(callable), restrictions )); } } return(null); }
private MetaObject MakeArrayIndexRule(string oper, MetaObject[] args) { if (CanConvertFrom(GetArgType(args, 1), typeof(int), false, NarrowingLevel.All)) { Restrictions restrictions = Restrictions.GetTypeRestriction(args[0].Expression, args[0].LimitType).Merge(Restrictions.Combine(args)); if (oper == StandardOperators.GetItem) { return(new MetaObject( Ast.ArrayAccess( args[0].Expression, ConvertIfNeeded(args[1].Expression, typeof(int)) ), restrictions )); } else { return(new MetaObject( Ast.Assign( Ast.ArrayAccess( args[0].Expression, ConvertIfNeeded(args[1].Expression, typeof(int)) ), ConvertIfNeeded(args[2].Expression, args[0].LimitType.GetElementType()) ), restrictions.Merge(args[1].Restrictions) )); } } return(null); }