Fixes to the Type Binder and static method handling
This commit is contained in:
parent
3d9b7a53e9
commit
5646ff1da1
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.BaseTypes.ScriptFunction;
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
|
@ -71,6 +72,11 @@ namespace Upsilon.BaseTypes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (o is IEnumerable enumerable)
|
||||||
|
{
|
||||||
|
return new ListUserData(enumerable.Cast<object>().ToList());
|
||||||
|
}
|
||||||
|
|
||||||
return new GenericUserData(o);
|
return new GenericUserData(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,78 +25,7 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
|
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
{
|
{
|
||||||
var validMatch = true;
|
if (IsValidMatch(match, ref args))
|
||||||
var parameters = match.GetParameters();
|
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
|
||||||
{
|
|
||||||
var matchParameter = parameters[i];
|
|
||||||
if (args.Length <= i)
|
|
||||||
{
|
|
||||||
if (matchParameter.IsOptional)
|
|
||||||
return match;
|
|
||||||
validMatch = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var argument = args[i];
|
|
||||||
var argumentType = argument.GetType();
|
|
||||||
|
|
||||||
var typeCode = System.Type.GetTypeCode(matchParameter.ParameterType);
|
|
||||||
switch (typeCode)
|
|
||||||
{
|
|
||||||
case TypeCode.Boolean:
|
|
||||||
if (argument is ScriptBoolean b)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TypeCode.Char:
|
|
||||||
case TypeCode.String:
|
|
||||||
if (argument is ScriptString s)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TypeCode.Byte:
|
|
||||||
case TypeCode.Decimal:
|
|
||||||
case TypeCode.Double:
|
|
||||||
case TypeCode.Int16:
|
|
||||||
case TypeCode.Int32:
|
|
||||||
case TypeCode.Int64:
|
|
||||||
case TypeCode.SByte:
|
|
||||||
case TypeCode.Single:
|
|
||||||
case TypeCode.UInt16:
|
|
||||||
case TypeCode.UInt32:
|
|
||||||
case TypeCode.UInt64:
|
|
||||||
if (argument is ScriptNumber numeric)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TypeCode.Object:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!typeof(ScriptType).IsAssignableFrom(matchParameter.ParameterType) &&
|
|
||||||
argument is IUserData ud)
|
|
||||||
{
|
|
||||||
var csharpType = ud.GetCSharpType();
|
|
||||||
if (matchParameter.ParameterType.IsAssignableFrom(csharpType))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argumentType == typeof(ScriptNull))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matchParameter.ParameterType.IsAssignableFrom(argumentType))
|
|
||||||
{
|
|
||||||
validMatch = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validMatch)
|
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +33,83 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsValidMatch(MethodBase match, ref object[] args)
|
||||||
|
{
|
||||||
|
var validMatch = true;
|
||||||
|
var parameters = match.GetParameters();
|
||||||
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var matchParameter = parameters[i];
|
||||||
|
if (args.Length <= i)
|
||||||
|
{
|
||||||
|
if (matchParameter.IsOptional)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argument = args[i];
|
||||||
|
var argumentType = argument.GetType();
|
||||||
|
|
||||||
|
var typeCode = System.Type.GetTypeCode(matchParameter.ParameterType);
|
||||||
|
switch (typeCode)
|
||||||
|
{
|
||||||
|
case TypeCode.Boolean:
|
||||||
|
if (argument is ScriptBoolean b)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TypeCode.Char:
|
||||||
|
case TypeCode.String:
|
||||||
|
if (argument is ScriptString s)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TypeCode.Byte:
|
||||||
|
case TypeCode.Decimal:
|
||||||
|
case TypeCode.Double:
|
||||||
|
case TypeCode.Int16:
|
||||||
|
case TypeCode.Int32:
|
||||||
|
case TypeCode.Int64:
|
||||||
|
case TypeCode.SByte:
|
||||||
|
case TypeCode.Single:
|
||||||
|
case TypeCode.UInt16:
|
||||||
|
case TypeCode.UInt32:
|
||||||
|
case TypeCode.UInt64:
|
||||||
|
if (argument is ScriptNumber numeric)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TypeCode.Object:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeof(ScriptType).IsAssignableFrom(matchParameter.ParameterType) &&
|
||||||
|
argument is IUserData ud)
|
||||||
|
{
|
||||||
|
var csharpType = ud.GetCSharpType();
|
||||||
|
if (matchParameter.ParameterType.IsAssignableFrom(csharpType))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argumentType == typeof(ScriptNull))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchParameter.ParameterType.IsAssignableFrom(argumentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validMatch;
|
||||||
|
}
|
||||||
|
|
||||||
public override object ChangeType(object value, System.Type type, CultureInfo culture)
|
public override object ChangeType(object value, System.Type type, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (type.IsInstanceOfType(value))
|
if (type.IsInstanceOfType(value))
|
||||||
|
@ -185,7 +191,40 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
if (value is ListUserData d)
|
if (value is ListUserData d)
|
||||||
return d.List;
|
return d.List;
|
||||||
if (value is ScriptTable.ScriptTable table)
|
if (value is ScriptTable.ScriptTable table)
|
||||||
return table.EvaluationScope.Variables.Select(x => x.Value.ToCSharpObject());
|
{
|
||||||
|
var generics = type.GetGenericArguments();
|
||||||
|
if (generics.Length > 0)
|
||||||
|
{
|
||||||
|
var l1 = typeof(List<>);
|
||||||
|
var requiredListType = l1.MakeGenericType(generics[0]);
|
||||||
|
var list = (IList)Activator.CreateInstance(requiredListType);
|
||||||
|
foreach (var variable in table.EvaluationScope.Variables)
|
||||||
|
{
|
||||||
|
list.Add(variable.Value.ToCSharpObject());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return table.EvaluationScope.Variables.Select(x => x.Value.ToCSharpObject()).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
if (value is ListUserData d)
|
||||||
|
return d.List;
|
||||||
|
if (value is ScriptTable.ScriptTable table)
|
||||||
|
{
|
||||||
|
var generics = type.GetGenericArguments();
|
||||||
|
var l1 = typeof(List<>);
|
||||||
|
var requiredListType = l1.MakeGenericType(generics[0]);
|
||||||
|
var list = (IList)Activator.CreateInstance(requiredListType);
|
||||||
|
foreach (var variable in table.EvaluationScope.Variables)
|
||||||
|
{
|
||||||
|
list.Add(variable.Value.ToCSharpObject());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var isScriptTypeRequired = typeof(ScriptType).IsAssignableFrom(type);
|
var isScriptTypeRequired = typeof(ScriptType).IsAssignableFrom(type);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.StandardLibraries;
|
using Upsilon.StandardLibraries;
|
||||||
|
@ -73,43 +73,24 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
return MethodParts;
|
return MethodParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodInfo GetMethod(ref object[] parameters)
|
public MethodInfo GetMethod(ref object[] arguments)
|
||||||
{
|
{
|
||||||
foreach (var userDataMethodPart in MethodParts)
|
foreach (var userDataMethodPart in MethodParts)
|
||||||
{
|
{
|
||||||
if (userDataMethodPart.Parameters.Length < parameters.Length)
|
var methodBase = userDataMethodPart.Method;
|
||||||
continue;
|
if (UpsilonBinder.Default.IsValidMatch(methodBase, ref arguments))
|
||||||
bool valid = true;
|
|
||||||
for (var index = 0; index < userDataMethodPart.Parameters.Length; index++)
|
|
||||||
{
|
{
|
||||||
var userDataMethodParameter = userDataMethodPart.Parameters[index];
|
var parameters = methodBase.GetParameters();
|
||||||
if (index >= parameters.Length)
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
if (userDataMethodParameter.IsOptional)
|
var argument = arguments[i];
|
||||||
return userDataMethodPart.Method;
|
var requiredType = parameters[i].ParameterType;
|
||||||
valid = false;
|
arguments[i] =
|
||||||
break;
|
UpsilonBinder.Default.ChangeType(argument, requiredType, CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
var parameter = parameters[index];
|
|
||||||
var parameterType = parameter.GetType();
|
|
||||||
if (parameterType.IsGenericType) parameter = parameterType.GetGenericTypeDefinition();
|
|
||||||
if (userDataMethodParameter.Type != parameterType &&
|
|
||||||
!userDataMethodParameter.Type.IsAssignableFrom(parameterType))
|
|
||||||
{
|
|
||||||
if (parameter is ScriptType t)
|
|
||||||
{
|
|
||||||
if (userDataMethodParameter.Type.IsAssignableFrom(t.GetCSharpType()))
|
|
||||||
{
|
|
||||||
parameters[index] = ((ScriptType) parameter).ToCSharpObject();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valid) return userDataMethodPart.Method;
|
return methodBase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in New Issue