diff --git a/Upsilon/BaseTypes/TypeConversion.cs b/Upsilon/BaseTypes/TypeConversion.cs index cf2981a..5900d21 100644 --- a/Upsilon/BaseTypes/TypeConversion.cs +++ b/Upsilon/BaseTypes/TypeConversion.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Linq; using System.Reflection; using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.ScriptFunction; @@ -71,6 +72,11 @@ namespace Upsilon.BaseTypes } } + if (o is IEnumerable enumerable) + { + return new ListUserData(enumerable.Cast().ToList()); + } + return new GenericUserData(o); } diff --git a/Upsilon/BaseTypes/UserData/UpsilonBinder.cs b/Upsilon/BaseTypes/UserData/UpsilonBinder.cs index 9e4f7a8..364d876 100644 --- a/Upsilon/BaseTypes/UserData/UpsilonBinder.cs +++ b/Upsilon/BaseTypes/UserData/UpsilonBinder.cs @@ -25,78 +25,7 @@ namespace Upsilon.BaseTypes.UserData foreach (var match in matches) { - 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 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) + if (IsValidMatch(match, ref args)) return match; } @@ -104,6 +33,83 @@ namespace Upsilon.BaseTypes.UserData 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) { if (type.IsInstanceOfType(value)) @@ -185,7 +191,40 @@ namespace Upsilon.BaseTypes.UserData if (value is ListUserData d) return d.List; 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); diff --git a/Upsilon/BaseTypes/UserData/UserDataMethod.cs b/Upsilon/BaseTypes/UserData/UserDataMethod.cs index 6e229d0..160635d 100644 --- a/Upsilon/BaseTypes/UserData/UserDataMethod.cs +++ b/Upsilon/BaseTypes/UserData/UserDataMethod.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Linq; +using System.Globalization; using System.Reflection; using Upsilon.Evaluator; using Upsilon.StandardLibraries; @@ -73,43 +73,24 @@ namespace Upsilon.BaseTypes.UserData return MethodParts; } - public MethodInfo GetMethod(ref object[] parameters) + public MethodInfo GetMethod(ref object[] arguments) { foreach (var userDataMethodPart in MethodParts) { - if (userDataMethodPart.Parameters.Length < parameters.Length) - continue; - bool valid = true; - for (var index = 0; index < userDataMethodPart.Parameters.Length; index++) + var methodBase = userDataMethodPart.Method; + if (UpsilonBinder.Default.IsValidMatch(methodBase, ref arguments)) { - var userDataMethodParameter = userDataMethodPart.Parameters[index]; - if (index >= parameters.Length) + var parameters = methodBase.GetParameters(); + for (var i = 0; i < parameters.Length; i++) { - if (userDataMethodParameter.IsOptional) - return userDataMethodPart.Method; - valid = false; - break; + var argument = arguments[i]; + var requiredType = parameters[i].ParameterType; + arguments[i] = + 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;