Rework of function calling to handle generics better
This commit is contained in:
parent
43d9360145
commit
422de5d4eb
|
@ -49,13 +49,11 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
objects.Add(script);
|
||||
if (_passScopeReference)
|
||||
objects.Add(scope);
|
||||
objects.AddRange(_directTypeManipulation
|
||||
? variables.Select(x => (object) x).ToList()
|
||||
: variables.Select(x => x.ToCSharpObject()).ToList());
|
||||
objects.AddRange(variables.Select(x => (object) x).ToList() );
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, System.Type.DefaultBinder,
|
||||
result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, UpsilonBinder.Default,
|
||||
_object, objects.ToArray());
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
|
|
|
@ -22,6 +22,10 @@ namespace Upsilon.BaseTypes
|
|||
return new ScriptNumberLong(i);
|
||||
case short s:
|
||||
return new ScriptNumberLong(s);
|
||||
case sbyte s:
|
||||
return new ScriptNumberLong(s);
|
||||
case byte s:
|
||||
return new ScriptNumberLong(s);
|
||||
case long i:
|
||||
return new ScriptNumberLong(i);
|
||||
case float f:
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
public class UpsilonBinder : System.Reflection.Binder
|
||||
{
|
||||
public static readonly UpsilonBinder Default = new UpsilonBinder();
|
||||
|
||||
public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] matches, ref object[] args, ParameterModifier[] modifiers,
|
||||
CultureInfo culture, string[] names, out object state)
|
||||
{
|
||||
state = null;
|
||||
|
||||
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 (!matchParameter.ParameterType.IsAssignableFrom(argumentType))
|
||||
{
|
||||
validMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (validMatch)
|
||||
return match;
|
||||
}
|
||||
|
||||
state = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override object ChangeType(object value, System.Type type, CultureInfo culture)
|
||||
{
|
||||
if (type.IsInstanceOfType(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
var typeCode = System.Type.GetTypeCode(type);
|
||||
switch (typeCode)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
if (value is ScriptBoolean b)
|
||||
{
|
||||
return b.Value;
|
||||
}
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
case TypeCode.String:
|
||||
if (value is ScriptString s)
|
||||
{
|
||||
return s.Value;
|
||||
}
|
||||
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 (value is ScriptNumber numeric)
|
||||
{
|
||||
return Convert.ChangeType(numeric.ToCSharpObject(), typeCode);
|
||||
}
|
||||
break;
|
||||
case TypeCode.Object:
|
||||
if (value is ScriptType t)
|
||||
{
|
||||
return t.ToCSharpObject();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var isScriptTypeRequired = typeof(ScriptType).IsAssignableFrom(type);
|
||||
var isScriptType = value is ScriptType;
|
||||
if (!isScriptTypeRequired && isScriptType)
|
||||
{
|
||||
return ((ScriptType)value).ToCSharpObject();
|
||||
}
|
||||
|
||||
if (isScriptTypeRequired && !isScriptType)
|
||||
{
|
||||
return value.ToScriptType();
|
||||
}
|
||||
|
||||
if (type == typeof(IIterable))
|
||||
{
|
||||
var valueType = value.GetType();
|
||||
if (typeof(IDictionary).IsAssignableFrom(valueType))
|
||||
{
|
||||
return new DictionaryUserData((IDictionary) value);
|
||||
}
|
||||
if (typeof(IList).IsAssignableFrom(valueType))
|
||||
{
|
||||
return new ListUserData((IList) value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public override void ReorderArgumentArray(ref object[] args, object state)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] matches, System.Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
|
||||
}
|
||||
|
||||
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, System.Type returnType, System.Type[] indexes,
|
||||
ParameterModifier[] modifiers)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Upsilon.BaseTypes.ScriptFunction;
|
||||
|
@ -59,11 +60,17 @@ namespace Upsilon.BaseTypes.UserData
|
|||
member = member.ToLowerInvariant();
|
||||
if (Variables.TryGetValue(member, out var info))
|
||||
{
|
||||
return (info.GetValue(value).ToScriptType(), false, null);
|
||||
var field = value.GetType().GetField(info.Name);
|
||||
return (field.GetValue(value).ToScriptType(), false, null);
|
||||
}
|
||||
if (Properties.TryGetValue(member, out var property))
|
||||
if (Properties.TryGetValue(member, out var prop))
|
||||
{
|
||||
return (property.GetValue(value).ToScriptType(), false, null);
|
||||
var property = value.GetType().GetProperty(prop.Name);
|
||||
if (property != null)
|
||||
{
|
||||
return (property.GetValue(value, BindingFlags.GetProperty, UpsilonBinder.Default, null,
|
||||
CultureInfo.InvariantCulture).ToScriptType(), false, null);
|
||||
}
|
||||
}
|
||||
if (Methods.TryGetValue(member, out var method))
|
||||
{
|
||||
|
@ -80,17 +87,25 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return (true, "Invalid Type");
|
||||
if (Variables.TryGetValue(member, out var info))
|
||||
{
|
||||
info.SetValue(value, newValue.ToCSharpObject());
|
||||
var field = value.GetType().GetField(info.Name);
|
||||
field.SetValue(value, newValue, BindingFlags.SetField,
|
||||
UpsilonBinder.Default, CultureInfo.InvariantCulture);
|
||||
return (false, null);
|
||||
}
|
||||
if (Properties.TryGetValue(member, out var property))
|
||||
if (Properties.TryGetValue(member, out var prop))
|
||||
{
|
||||
if (property.SetMethod == null || property.SetMethod.IsPrivate)
|
||||
var property = value.GetType().GetProperty(prop.Name);
|
||||
if (property != null)
|
||||
{
|
||||
return (true, $"Property '{member}' on type '{Type}' does not have a publicly available setter.");
|
||||
if (property.SetMethod == null || property.SetMethod.IsPrivate)
|
||||
{
|
||||
return (true, $"Property '{member}' on type '{Type}' does not have a publicly available setter.");
|
||||
}
|
||||
|
||||
property.SetValue(value, newValue, BindingFlags.SetProperty, UpsilonBinder.Default, null,
|
||||
CultureInfo.InvariantCulture);
|
||||
return (false, null);
|
||||
}
|
||||
property.SetValue(value, newValue.ToCSharpObject());
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
return (true, $"Cannot find member '{member}' on type '{Type}'");
|
||||
|
|
|
@ -16,11 +16,18 @@ namespace Upsilon.StandardLibraries
|
|||
[ScriptFunction("assert", "Asserts that the parameter passed is true. Throws an exception if it is not true. " +
|
||||
"Can take a message to show in the exception, otherwise throws with message \"assertion failed!\"",
|
||||
directScriptManipulation: true)]
|
||||
public void Assert(ScriptBoolean boolean, ScriptString message = null)
|
||||
public void Assert(ScriptBoolean boolean)
|
||||
{
|
||||
if (!boolean)
|
||||
{
|
||||
Error(message ?? new ScriptString("assertion failed!"));
|
||||
Error(new ScriptString("assertion failed!"));
|
||||
}
|
||||
}
|
||||
public void Assert(ScriptBoolean boolean, ScriptString message)
|
||||
{
|
||||
if (!boolean)
|
||||
{
|
||||
Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue