/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Microsoft Public License. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Microsoft Public License, please send an email to
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Dynamic.Binders;
using Microsoft.Scripting.Actions.Calls;
using Microsoft.Scripting.Generation;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;
using AstUtils = Microsoft.Scripting.Ast.Utils;
namespace Microsoft.Scripting.Actions {
using Ast = System.Linq.Expressions.Expression;
public partial class DefaultBinder : ActionBinder {
#region Public APIs
///
/// Performs binding against a set of overloaded methods using the specified arguments. All arguments
/// are treated as positional arguments.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args) {
return CallMethod(
parameterBinder,
targets,
args,
new CallSignature(args.Count),
Restrictions.Empty
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. All arguments
/// are treated as positional arguments.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The maximum narrowing level for arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The minimum narrowing level for the arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, NarrowingLevel minLevel, NarrowingLevel maxLevel) {
return CallWorker(
parameterBinder,
targets,
args,
new CallSignature(args.Count),
CallTypes.None,
Restrictions.Empty,
minLevel,
maxLevel,
null
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature) {
return CallMethod(parameterBinder, targets, args, signature, Restrictions.Empty);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// The name of the method or null to use the name from targets.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, string name) {
return CallMethod(parameterBinder, targets, args, signature, Restrictions.Empty, name);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, Restrictions restrictions) {
return CallWorker(
parameterBinder,
targets,
args,
signature,
CallTypes.None,
restrictions,
NarrowingLevel.None,
NarrowingLevel.All,
null
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// The name of the method or null to use the name from targets.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, Restrictions restrictions, string name) {
return CallWorker(
parameterBinder,
targets,
args,
signature,
CallTypes.None,
restrictions,
NarrowingLevel.None,
NarrowingLevel.All,
name
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments and the specified
/// instance argument. The arguments are consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The instance which will be provided for dispatching to an instance method.
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// A meta object which results from the call.
public MetaObject CallInstanceMethod(ParameterBinder parameterBinder, IList targets, MetaObject instance, IList args, CallSignature signature, Restrictions restrictions) {
ContractUtils.RequiresNotNull(instance, "instance");
ContractUtils.RequiresNotNull(parameterBinder, "parameterBinder");
return CallWorker(
parameterBinder,
targets,
ArrayUtils.Insert(instance, args),
signature,
CallTypes.ImplicitInstance,
restrictions,
NarrowingLevel.None,
NarrowingLevel.All,
null
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// The maximum narrowing level for arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The minimum narrowing level for the arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The resulting binding target which can be used for producing error information.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, out BindingTarget target) {
return CallWorker(
parameterBinder,
targets,
args,
signature,
CallTypes.None,
restrictions,
minLevel,
maxLevel,
null,
out target
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments. The arguments are
/// consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// The maximum narrowing level for arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The minimum narrowing level for the arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The resulting binding target which can be used for producing error information.
/// The name of the method or null to use the name from targets.
/// A meta object which results from the call.
public MetaObject CallMethod(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, string name, out BindingTarget target) {
return CallWorker(
parameterBinder,
targets,
args,
signature,
CallTypes.None,
restrictions,
minLevel,
maxLevel,
name,
out target
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments and the specified
/// instance argument. The arguments are consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// The instance which will be provided for dispatching to an instance method.
/// The maximum narrowing level for arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The minimum narrowing level for the arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The resulting binding target which can be used for producing error information.
/// A meta object which results from the call.
public MetaObject CallInstanceMethod(ParameterBinder parameterBinder, IList targets, MetaObject instance, IList args, CallSignature signature, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, out BindingTarget target) {
return CallWorker(
parameterBinder,
targets,
ArrayUtils.Insert(instance, args),
signature,
CallTypes.ImplicitInstance,
restrictions,
minLevel,
maxLevel,
null,
out target
);
}
///
/// Performs binding against a set of overloaded methods using the specified arguments and the specified
/// instance argument. The arguments are consumed as specified by the CallSignature object.
///
/// ParameterBinder used to map arguments to parameters.
/// The methods to be called
/// The arguments for the call
/// The call signature which specified how the arguments will be consumed
/// Additional restrictions which should be applied to the resulting MetaObject.
/// The instance which will be provided for dispatching to an instance method.
/// The maximum narrowing level for arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The minimum narrowing level for the arguments. The current narrowing level is flowed thorugh to the DefaultBinder.
/// The resulting binding target which can be used for producing error information.
/// The name of the method or null to use the name from targets.
/// A meta object which results from the call.
public MetaObject CallInstanceMethod(ParameterBinder parameterBinder, IList targets, MetaObject instance, IList args, CallSignature signature, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, string name, out BindingTarget target) {
return CallWorker(
parameterBinder,
targets,
ArrayUtils.Insert(instance, args),
signature,
CallTypes.ImplicitInstance,
restrictions,
minLevel,
maxLevel,
name,
out target
);
}
private MetaObject CallWorker(ParameterBinder parameterBinder, IList targets, IList args, CallSignature signature, CallTypes callType, Restrictions restrictions, NarrowingLevel minLevel, NarrowingLevel maxLevel, string name) {
BindingTarget dummy;
return CallWorker(parameterBinder, targets, args, signature, callType, restrictions, minLevel, maxLevel, name, out dummy);
}
private MetaObject CallWorker(ParameterBinder parameterBinder, IList targets, IList 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);
}
#endregion
#region Restriction helpers
private static Restrictions MakeSplatTests(CallTypes callType, CallSignature signature, IList args) {
return MakeSplatTests(callType, signature, false, args);
}
///
/// Makes test for param arrays and param dictionary parameters.
///
private static Restrictions MakeSplatTests(CallTypes callType, CallSignature signature, bool testTypes, IList args) {
Restrictions res = Restrictions.Empty;
if (signature.HasListArgument()) {
res = MakeParamsArrayTest(callType, signature, testTypes, args);
}
if (signature.HasDictionaryArgument()) {
res = res.Merge(MakeParamsDictionaryTest(args, testTypes));
}
return res;
}
///
/// Pulls out the right argument to build the splat test. MakeParamsTest makes the actual test.
///
private static Restrictions MakeParamsArrayTest(CallTypes callType, CallSignature signature, bool testTypes, IList args) {
int listIndex = signature.IndexOf(ArgumentType.List);
Debug.Assert(listIndex != -1);
if (callType == CallTypes.ImplicitInstance) {
listIndex++;
}
return MakeParamsTest(args[listIndex].Value, args[listIndex].Expression, testTypes);
}
///
/// Builds the restrictions for calling with a splatted argument array. Ensures that the
/// argument is still an ICollection of object and that it has the same number of arguments.
///
private static Restrictions MakeParamsTest(object paramArg, Expression listArg, bool testTypes) {
IList