progress
This commit is contained in:
parent
16e76d6b31
commit
484dbfc9d9
529 changed files with 113694 additions and 0 deletions
683
AspClassic.VBScript/Runtime/RuntimeHelpers.cs
Normal file
683
AspClassic.VBScript/Runtime/RuntimeHelpers.cs
Normal file
|
@ -0,0 +1,683 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Dynamic;
|
||||
#if USE35
|
||||
using AspClassic.Scripting.Ast;
|
||||
using AspClassic.Scripting.Utils;
|
||||
#else
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
using System.Runtime.CompilerServices;
|
||||
using Path = System.IO.Path;
|
||||
using File = System.IO.File;
|
||||
using Directory = System.IO.Directory;
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
#if SILVERLIGHT
|
||||
using w = System.Windows;
|
||||
using System.Windows.Resources;
|
||||
#endif
|
||||
|
||||
namespace Dlrsoft.VBScript.Runtime
|
||||
{
|
||||
|
||||
// RuntimeHelpers is a collection of functions that perform operations at
|
||||
// runtime of Sympl code, such as performing an import or eq.
|
||||
//
|
||||
public static class RuntimeHelpers {
|
||||
// VBScriptImport takes the runtime and module as context for the import.
|
||||
// It takes a list of names, what, that either identify a (possibly dotted
|
||||
// sequence) of names to fetch from Globals or a file name to load. Names
|
||||
// is a list of names to fetch from the final object that what indicates
|
||||
// and then set each name in module. Renames is a list of names to add to
|
||||
// module instead of names. If names is empty, then the name set in
|
||||
// module is the last name in what. If renames is not empty, it must have
|
||||
// the same cardinality as names.
|
||||
//
|
||||
public static object VBScriptImport(VBScript runtime, IDynamicMetaObjectProvider module,
|
||||
string[] what, string[] names,
|
||||
string[] renames)
|
||||
{
|
||||
// Get object or file scope.
|
||||
object value = null;
|
||||
if (what.Length == 1)
|
||||
{
|
||||
string name = what[0];
|
||||
if (DynamicObjectHelpers.HasMember(runtime.Globals, name))
|
||||
{
|
||||
value = DynamicObjectHelpers.GetMember(runtime.Globals, name);
|
||||
// Since runtime.Globals has Sympl's reflection of namespaces and
|
||||
// types, we pick those up first above and don't risk hitting a
|
||||
// NamespaceTracker for assemblies added when we initialized Sympl.
|
||||
// The next check will correctly look up case-INsensitively for
|
||||
// globals the host adds to ScriptRuntime.Globals.
|
||||
}
|
||||
else if (DynamicObjectHelpers.HasMember(runtime.DlrGlobals, name))
|
||||
{
|
||||
value = DynamicObjectHelpers.GetMember(runtime.DlrGlobals, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Import: can't find name in globals -- " + name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// What has more than one name, must be Globals access.
|
||||
value = runtime.Globals;
|
||||
// For more correctness and generality, shouldn't assume all
|
||||
// globals are dynamic objects, or that a look up like foo.bar.baz
|
||||
// cascades through all dynamic objects.
|
||||
// Would need to manually create a CallSite here with Sympl's
|
||||
// GetMemberBinder, and think about a caching strategy per name.
|
||||
foreach (string name in what)
|
||||
{
|
||||
value = DynamicObjectHelpers.GetMember(
|
||||
(IDynamicMetaObjectProvider)value, name);
|
||||
}
|
||||
}
|
||||
// Assign variables in module.
|
||||
if (names.Length == 0)
|
||||
{
|
||||
if (renames.Length == 0)
|
||||
{
|
||||
DynamicObjectHelpers.SetMember((IDynamicMetaObjectProvider)module,
|
||||
what[what.Length - 1], value);
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicObjectHelpers.SetMember((IDynamicMetaObjectProvider)module,
|
||||
renames[0], value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (renames.Length == 0) renames = names;
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i];
|
||||
string rename = renames[i];
|
||||
DynamicObjectHelpers.SetMember(
|
||||
(IDynamicMetaObjectProvider)module, rename,
|
||||
DynamicObjectHelpers.GetMember(
|
||||
(IDynamicMetaObjectProvider)value, name));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} // SymplImport
|
||||
|
||||
// Uses of the 'eq' keyword form in Sympl compile to a call to this
|
||||
// helper function.
|
||||
//
|
||||
public static bool SymplEq (object x, object y) {
|
||||
if (x == null)
|
||||
return y == null;
|
||||
else if (y == null)
|
||||
return x == null;
|
||||
else {
|
||||
var xtype = x.GetType();
|
||||
var ytype = y.GetType();
|
||||
if (xtype.IsPrimitive && xtype != typeof(string) &&
|
||||
ytype.IsPrimitive && ytype != typeof(string))
|
||||
return x.Equals(y);
|
||||
else
|
||||
return object.ReferenceEquals(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Array Utilities (slicing) and some LINQ helpers
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
public static T[] RemoveFirstElt<T>(IList<T> list) {
|
||||
// Make array ...
|
||||
if (list.Count == 0) {
|
||||
return new T[0];
|
||||
}
|
||||
T[] res = new T[list.Count];
|
||||
list.CopyTo(res, 0);
|
||||
// Shift result
|
||||
return ShiftLeft(res, 1);
|
||||
}
|
||||
|
||||
public static T[] RemoveFirstElt<T>(T[] array) {
|
||||
return ShiftLeft(array, 1);
|
||||
}
|
||||
|
||||
private static T[] ShiftLeft<T>(T[] array, int count) {
|
||||
//ContractUtils.RequiresNotNull(array, "array");
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("count");
|
||||
T[] result = new T[array.Length - count];
|
||||
System.Array.Copy(array, count, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T[] RemoveLast<T>(T[] array) {
|
||||
//ContractUtils.RequiresNotNull(array, "array");
|
||||
System.Array.Resize(ref array, array.Length - 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
#if USE35
|
||||
// Need to reproduce these helpers from DLR codeplex-only sources and
|
||||
// from LINQ functionality to avoid referencing System.Core.dll and
|
||||
// AspClassic.Scripting.Core.dll for internal building.
|
||||
|
||||
internal static IEnumerable<U> Select<T, U>(this IEnumerable<T> enumerable, AspClassic.Scripting.Utils.Func<T, U> select) {
|
||||
foreach (T t in enumerable) {
|
||||
yield return select(t);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<T> Where<T>(this IEnumerable<T> enumerable, AspClassic.Scripting.Utils.Func<T, bool> where) {
|
||||
foreach (T t in enumerable) {
|
||||
if (where(t)) {
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool Any<T>(this IEnumerable<T> source, AspClassic.Scripting.Utils.Func<T, bool> predicate) {
|
||||
foreach (T element in source) {
|
||||
if (predicate(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static T[] ToArray<T>(this IEnumerable<T> enumerable) {
|
||||
var c = enumerable as ICollection<T>;
|
||||
if (c != null) {
|
||||
var result = new T[c.Count];
|
||||
c.CopyTo(result, 0);
|
||||
return result;
|
||||
}
|
||||
return new List<T>(enumerable).ToArray();
|
||||
}
|
||||
|
||||
internal static TSource Last<TSource>(this IList<TSource> list) {
|
||||
if (list == null) throw new ArgumentNullException("list");
|
||||
int count = list.Count;
|
||||
if (count > 0) return list[count - 1];
|
||||
throw new ArgumentException("list is empty");
|
||||
}
|
||||
|
||||
internal static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value) {
|
||||
IEqualityComparer<TSource> comparer = EqualityComparer<TSource>.Default;
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
foreach (TSource element in source)
|
||||
if (comparer.Equals(element, value)) return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// Utilities used by binders at runtime
|
||||
///////////////////////////////////////
|
||||
|
||||
// ParamsMatchArgs returns whether the args are assignable to the parameters.
|
||||
// We specially check for our TypeModel that wraps .NET's RuntimeType, and
|
||||
// elsewhere we detect the same situation to convert the TypeModel for calls.
|
||||
//
|
||||
// Consider checking p.IsByRef and returning false since that's not CLS.
|
||||
//
|
||||
// Could check for a.HasValue and a.Value is None and
|
||||
// ((paramtype is class or interface) or (paramtype is generic and
|
||||
// nullable<t>)) to support passing nil anywhere.
|
||||
//
|
||||
public static bool ParametersMatchArguments(ParameterInfo[] parameters,
|
||||
DynamicMetaObject[] args) {
|
||||
// We only call this after filtering members by this constraint.
|
||||
Debug.Assert(args.Length == parameters.Length,
|
||||
"Internal: args are not same len as params?!");
|
||||
for (int i = 0; i < args.Length; i++) {
|
||||
var paramType = parameters[i].ParameterType;
|
||||
// We consider arg of TypeModel and param of Type to be compatible.
|
||||
if (paramType == typeof(Type) &&
|
||||
(args[i].LimitType == typeof(TypeModel))) {
|
||||
continue;
|
||||
}
|
||||
//LC OK to assign null to any reference type
|
||||
if (!paramType.IsValueType && args[i].Value == null)
|
||||
continue;
|
||||
|
||||
if (!paramType
|
||||
// Could check for HasValue and Value==null AND
|
||||
// (paramtype is class or interface) or (is generic
|
||||
// and nullable<T>) ... to bind nullables and null.
|
||||
.IsAssignableFrom(args[i].LimitType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int[] GetMatchRank(ParameterInfo[] parameters,
|
||||
DynamicMetaObject[] args)
|
||||
{
|
||||
Debug.Assert(args.Length == parameters.Length,
|
||||
"Internal: args are not same len as params?!");
|
||||
int[] rank = new int[parameters.Length];
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var paramType = parameters[i].ParameterType;
|
||||
// We consider arg of TypeModel and param of Type to be compatible.
|
||||
if (paramType == typeof(Type) &&
|
||||
(args[i].LimitType == typeof(TypeModel)))
|
||||
{
|
||||
rank[i] = 0;
|
||||
}
|
||||
else if (paramType == args[i].LimitType)
|
||||
{
|
||||
rank[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rank[i] = 1;
|
||||
}
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
public static MethodInfo ResolveOverload(IList<MethodInfo> mis, DynamicMetaObject[] args)
|
||||
{
|
||||
MethodInfo best = mis[0];
|
||||
int[] bestRank = GetMatchRank(mis[0].GetParameters(), args);
|
||||
foreach (MethodInfo mi in mis)
|
||||
{
|
||||
int[] rank = GetMatchRank(mi.GetParameters(), args);
|
||||
if (Compare(rank, bestRank) < 0)
|
||||
{
|
||||
best = mi;
|
||||
bestRank = rank;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
private static int Compare(int[] a, int[] b)
|
||||
{
|
||||
for (int i = 0; i < a.Length; i++)
|
||||
{
|
||||
int result = a[i].CompareTo(b[i]);
|
||||
if (result == 0)
|
||||
continue;
|
||||
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns a DynamicMetaObject with an expression that fishes the .NET
|
||||
// RuntimeType object from the TypeModel MO.
|
||||
//
|
||||
public static DynamicMetaObject GetRuntimeTypeMoFromModel(
|
||||
DynamicMetaObject typeModelMO) {
|
||||
Debug.Assert((typeModelMO.LimitType == typeof(TypeModel)),
|
||||
"Internal: MO is not a TypeModel?!");
|
||||
// Get tm.ReflType
|
||||
var pi = typeof(TypeModel).GetProperty("ReflType");
|
||||
Debug.Assert(pi != null);
|
||||
return new DynamicMetaObject(
|
||||
Expression.Property(
|
||||
Expression.Convert(typeModelMO.Expression, typeof(TypeModel)),
|
||||
pi),
|
||||
typeModelMO.Restrictions.Merge(
|
||||
BindingRestrictions.GetTypeRestriction(
|
||||
typeModelMO.Expression, typeof(TypeModel)))//,
|
||||
// Must supply a value to prevent binder FallbackXXX methods
|
||||
// from infinitely looping if they do not check this MO for
|
||||
// HasValue == false and call Defer. After Sympl added Defer
|
||||
// checks, we could verify, say, FallbackInvokeMember by no
|
||||
// longer passing a value here.
|
||||
//((TypeModel)typeModelMO.Value).ReflType
|
||||
);
|
||||
}
|
||||
|
||||
// Returns list of Convert exprs converting args to param types. If an arg
|
||||
// is a TypeModel, then we treat it special to perform the binding. We need
|
||||
// to map from our runtime model to .NET's RuntimeType object to match.
|
||||
//
|
||||
// To call this function, args and pinfos must be the same length, and param
|
||||
// types must be assignable from args.
|
||||
//
|
||||
// NOTE, if using this function, then need to use GetTargetArgsRestrictions
|
||||
// and make sure you're performing the same conversions as restrictions.
|
||||
//
|
||||
public static Expression[] ConvertArguments(
|
||||
DynamicMetaObject[] args, ParameterInfo[] ps) {
|
||||
Debug.Assert(args.Length == ps.Length,
|
||||
"Internal: args are not same len as params?!");
|
||||
Expression[] callArgs = new Expression[args.Length];
|
||||
for (int i = 0; i < args.Length; i++) {
|
||||
Expression argExpr = args[i].Expression;
|
||||
if (args[i].LimitType == typeof(TypeModel) &&
|
||||
ps[i].ParameterType == typeof(Type)) {
|
||||
// Get arg.ReflType
|
||||
argExpr = GetRuntimeTypeMoFromModel(args[i]).Expression;
|
||||
}
|
||||
Type paramType;
|
||||
if (ps[i].ParameterType.IsByRef)
|
||||
{
|
||||
paramType = ps[i].ParameterType.GetElementType();
|
||||
}
|
||||
else
|
||||
{
|
||||
paramType = ps[i].ParameterType;
|
||||
}
|
||||
if (argExpr.Type != paramType)
|
||||
{
|
||||
argExpr = Expression.Convert(argExpr, paramType);
|
||||
}
|
||||
callArgs[i] = argExpr;
|
||||
}
|
||||
return callArgs;
|
||||
}
|
||||
|
||||
public static Expression ConvertExpression(Expression expr, Type type)
|
||||
{
|
||||
if (type == expr.Type)
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CStr"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CLng"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CDbl"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CBool"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(decimal))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CCur"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CDate"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(short))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CInt"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CSng"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else if (type == typeof(byte))
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(BuiltInFunctions).GetMethod("CByte"),
|
||||
expr
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Expression.Convert(expr, type);
|
||||
}
|
||||
}
|
||||
|
||||
// GetTargetArgsRestrictions generates the restrictions needed for the
|
||||
// MO resulting from binding an operation. This combines all existing
|
||||
// restrictions and adds some for arg conversions. targetInst indicates
|
||||
// whether to restrict the target to an instance (for operations on type
|
||||
// objects) or to a type (for operations on an instance of that type).
|
||||
//
|
||||
// NOTE, this function should only be used when the caller is converting
|
||||
// arguments to the same types as these restrictions.
|
||||
//
|
||||
public static BindingRestrictions GetTargetArgsRestrictions(
|
||||
DynamicMetaObject target, DynamicMetaObject[] args,
|
||||
bool instanceRestrictionOnTarget){
|
||||
// Important to add existing restriction first because the
|
||||
// DynamicMetaObjects (and possibly values) we're looking at depend
|
||||
// on the pre-existing restrictions holding true.
|
||||
var restrictions = target.Restrictions.Merge(BindingRestrictions
|
||||
.Combine(args));
|
||||
//LC Use instance restriction is value is null
|
||||
if (instanceRestrictionOnTarget || target.Value == null)
|
||||
{
|
||||
restrictions = restrictions.Merge(
|
||||
BindingRestrictions.GetInstanceRestriction(
|
||||
target.Expression,
|
||||
target.Value
|
||||
));
|
||||
} else {
|
||||
restrictions = restrictions.Merge(
|
||||
BindingRestrictions.GetTypeRestriction(
|
||||
target.Expression,
|
||||
target.LimitType
|
||||
));
|
||||
}
|
||||
for (int i = 0; i < args.Length; i++) {
|
||||
BindingRestrictions r;
|
||||
if (args[i].HasValue && args[i].Value == null) {
|
||||
r = BindingRestrictions.GetInstanceRestriction(
|
||||
args[i].Expression, null);
|
||||
} else {
|
||||
r = BindingRestrictions.GetTypeRestriction(
|
||||
args[i].Expression, args[i].LimitType);
|
||||
}
|
||||
restrictions = restrictions.Merge(r);
|
||||
}
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
// Return the expression for getting target[indexes]
|
||||
//
|
||||
// Note, callers must ensure consistent restrictions are added for
|
||||
// the conversions on args and target.
|
||||
//
|
||||
public static Expression GetIndexingExpression(
|
||||
DynamicMetaObject target,
|
||||
DynamicMetaObject[] indexes) {
|
||||
//Debug.Assert(target.HasValue && target.LimitType != typeof(Array));
|
||||
|
||||
// ARRAY
|
||||
if (target.LimitType.IsArray)
|
||||
{
|
||||
var indexExpressions = indexes.Select(
|
||||
i => Expression.Convert(i.Expression, i.LimitType))
|
||||
.ToArray();
|
||||
|
||||
return Expression.ArrayAccess(
|
||||
Expression.Convert(target.Expression,
|
||||
target.LimitType),
|
||||
indexExpressions
|
||||
);
|
||||
// INDEXER
|
||||
} else {
|
||||
var props = target.LimitType.GetProperties();
|
||||
var indexers = props.
|
||||
Where(p => p.GetIndexParameters().Length > 0).ToArray();
|
||||
indexers = indexers.
|
||||
Where(idx => idx.GetIndexParameters().Length ==
|
||||
indexes.Length).ToArray();
|
||||
|
||||
var res = new List<PropertyInfo>();
|
||||
foreach (var idxer in indexers) {
|
||||
if (RuntimeHelpers.ParametersMatchArguments(
|
||||
idxer.GetIndexParameters(), indexes)) {
|
||||
// all parameter types match
|
||||
res.Add(idxer);
|
||||
}
|
||||
}
|
||||
if (res.Count == 0) {
|
||||
return Expression.Throw(
|
||||
Expression.New(
|
||||
typeof(MissingMemberException)
|
||||
.GetConstructor(new Type[] { typeof(string) }),
|
||||
Expression.Constant(
|
||||
"Can't bind because there is no matching indexer.")
|
||||
)
|
||||
);
|
||||
}
|
||||
return Expression.MakeIndex(
|
||||
Expression.Convert(target.Expression, target.LimitType),
|
||||
res[0], ConvertArguments(indexes, res[0].GetIndexParameters()));
|
||||
}
|
||||
}
|
||||
|
||||
// CreateThrow is a convenience function for when binders cannot bind.
|
||||
// They need to return a DynamicMetaObject with appropriate restrictions
|
||||
// that throws. Binders never just throw due to the protocol since
|
||||
// a binder or MO down the line may provide an implementation.
|
||||
//
|
||||
// It returns a DynamicMetaObject whose expr throws the exception, and
|
||||
// ensures the expr's type is object to satisfy the CallSite return type
|
||||
// constraint.
|
||||
//
|
||||
// A couple of calls to CreateThrow already have the args and target
|
||||
// restrictions merged in, but BindingRestrictions.Merge doesn't add
|
||||
// duplicates.
|
||||
//
|
||||
public static DynamicMetaObject CreateThrow
|
||||
(DynamicMetaObject target, DynamicMetaObject[] args,
|
||||
BindingRestrictions moreTests,
|
||||
Type exception, params object[] exceptionArgs) {
|
||||
Expression[] argExprs = null;
|
||||
Type[] argTypes = Type.EmptyTypes;
|
||||
int i;
|
||||
if (exceptionArgs != null) {
|
||||
i = exceptionArgs.Length;
|
||||
argExprs = new Expression[i];
|
||||
argTypes = new Type[i];
|
||||
i = 0;
|
||||
foreach (object o in exceptionArgs) {
|
||||
Expression e = Expression.Constant(o);
|
||||
argExprs[i] = e;
|
||||
argTypes[i] = e.Type;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
ConstructorInfo constructor = exception.GetConstructor(argTypes);
|
||||
if (constructor == null) {
|
||||
throw new ArgumentException(
|
||||
"Type doesn't have constructor with a given signature");
|
||||
}
|
||||
return new DynamicMetaObject(
|
||||
Expression.Throw(
|
||||
Expression.New(constructor, argExprs),
|
||||
// Force expression to be type object so that DLR CallSite
|
||||
// code things only type object flows out of the CallSite.
|
||||
typeof(object)),
|
||||
target.Restrictions.Merge(BindingRestrictions.Combine(args))
|
||||
.Merge(moreTests));
|
||||
}
|
||||
|
||||
// EnsureObjectResult wraps expr if necessary so that any binder or
|
||||
// DynamicMetaObject result expression returns object. This is required
|
||||
// by CallSites.
|
||||
//
|
||||
public static Expression EnsureObjectResult (Expression expr) {
|
||||
if (! expr.Type.IsValueType)
|
||||
return expr;
|
||||
if (expr.Type == typeof(void))
|
||||
return Expression.Block(
|
||||
expr, Expression.Default(typeof(object)));
|
||||
else
|
||||
return Expression.Convert(expr, typeof(object));
|
||||
}
|
||||
|
||||
public static Expression GetDefaultValue(Expression target)
|
||||
{
|
||||
return Expression.Call(
|
||||
typeof(HelperFunctions).GetMethod("GetDefaultPropertyValue", new Type[] { typeof(object) }),
|
||||
EnsureObjectResult(target)
|
||||
);
|
||||
}
|
||||
|
||||
public static List<MethodInfo> GetExtensionMethods(string name, DynamicMetaObject targetMO, DynamicMetaObject[] args)
|
||||
{
|
||||
List<MethodInfo> res = new List<MethodInfo>();
|
||||
#if !SILVERLIGHT
|
||||
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
#else
|
||||
foreach (w.AssemblyPart ap in w.Deployment.Current.Parts)
|
||||
{
|
||||
StreamResourceInfo sri = w.Application.GetResourceStream(new Uri(ap.Source, UriKind.Relative));
|
||||
Assembly a = new w.AssemblyPart().Load(sri.Stream);
|
||||
#endif
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = a.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
types = ex.Types;
|
||||
}
|
||||
|
||||
foreach (Type t in types)
|
||||
{
|
||||
if (t != null && t.IsPublic && t.IsAbstract && t.IsSealed)
|
||||
{
|
||||
foreach (MethodInfo mem in t.GetMember(name, MemberTypes.Method, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase))
|
||||
{
|
||||
//Should test using mem.IsDefined(attr) but typeof(ExtenssionAttribute) in Microsoft.Scription.Extensions and System.Core are infact two different types
|
||||
//Type attr = typeof(System.Runtime.CompilerServices.ExtensionAttribute);
|
||||
if (mem.GetParameters().Length == args.Length
|
||||
&& mem.GetParameters()[0].ParameterType == targetMO.RuntimeType)
|
||||
{
|
||||
if (RuntimeHelpers.ParametersMatchArguments(
|
||||
mem.GetParameters(), args))
|
||||
{
|
||||
res.Add(mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static bool IsNumericType(Type t)
|
||||
{
|
||||
if (t == typeof(int) || t == typeof(long) || t == typeof(float) || t == typeof(double) || t == typeof(decimal) || t == typeof(short) || t == typeof(sbyte))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
} // RuntimeHelpers
|
||||
|
||||
} // namespace
|
Loading…
Add table
Add a link
Reference in a new issue