Work on calling CSharp methods
This commit is contained in:
parent
efea92d32a
commit
e57129e116
|
@ -1,4 +1,5 @@
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes.ScriptFunction
|
namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
|
@ -15,6 +16,6 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope);
|
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Upsilon.BaseTypes.UserData;
|
using Upsilon.BaseTypes.UserData;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Exceptions;
|
||||||
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes.ScriptFunction
|
namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
|
@ -42,7 +45,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
return _method.GetMethods().First().Parameters;
|
return _method.GetMethods().First().Parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope)
|
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
||||||
{
|
{
|
||||||
var objects = new List<object>();
|
var objects = new List<object>();
|
||||||
if (_passScriptReference)
|
if (_passScriptReference)
|
||||||
|
@ -53,18 +56,76 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
object result;
|
object result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// If no parent object for the function was given, this is likely a lambda function, these need to be static
|
||||||
if (_object == null)
|
if (_object == null)
|
||||||
{
|
{
|
||||||
|
// grab the parameters, and just invoke it
|
||||||
var array = objects.ToArray();
|
var array = objects.ToArray();
|
||||||
var methodInfo = _method.GetMethod(ref array);
|
var methodInfo = _method.GetMethod(ref array);
|
||||||
result = methodInfo.Invoke(null, array);
|
result = methodInfo.Invoke(null, array);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, UpsilonBinder.Default,
|
// we create an array for the types of the objects
|
||||||
_object, objects.ToArray());
|
var convertedTypes = new System.Type[objects.Count];
|
||||||
|
for (var index = 0; index < objects.Count; index++)
|
||||||
|
{
|
||||||
|
// we grab the type of each parameter, and grab the underlying type if its a userdata object, as we need these
|
||||||
|
var arg = objects[index];
|
||||||
|
if (arg is IUserData ud)
|
||||||
|
{
|
||||||
|
convertedTypes[index] = ud.GetCSharpType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convertedTypes[index] = arg.GetType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab all public methods
|
||||||
|
var methods = _object.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
MethodInfo method = null;
|
||||||
|
var numberOfParametersFilled = -1;
|
||||||
|
// iterate over the methods on the object
|
||||||
|
foreach (var match in methods)
|
||||||
|
{
|
||||||
|
// if the method does not have the name we're looking for, continue
|
||||||
|
if (!string.Equals(match.Name, _method.Name)) continue;
|
||||||
|
// Use the type binder to check if the match is allowed
|
||||||
|
if (UpsilonBinder.Default.IsValidMatch(match, convertedTypes))
|
||||||
|
{
|
||||||
|
// grab the number of parameters on the match
|
||||||
|
var parCount = match.GetParameters().Length;
|
||||||
|
// We always try to grab the function with the most parameters
|
||||||
|
if (parCount > numberOfParametersFilled)
|
||||||
|
{
|
||||||
|
method = match;
|
||||||
|
numberOfParametersFilled = parCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we haven't found a method, we throw an exception
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
var (i, pos) = diagnostics.ScriptString.GetLinePosition(span.Start);
|
||||||
|
var line = diagnostics.ScriptString.GetLine(i);
|
||||||
|
throw new ScriptRuntimeException(
|
||||||
|
$"Can't find method {_method.Name} with parameter types {string.Join(", ", convertedTypes.Select(x => x.Name))} on type {_object.GetType().Name}",
|
||||||
|
i, pos, line);
|
||||||
|
}
|
||||||
|
// get the method parameters
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
var arguments = objects.ToArray();
|
||||||
|
// if the number of parameters does not match, we need to resize our given parameters
|
||||||
|
if (parameters.Length != arguments.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref arguments, parameters.Length);
|
||||||
|
}
|
||||||
|
// invoke the method
|
||||||
|
result = method.Invoke(_object, BindingFlags.InvokeMethod, UpsilonBinder.Default, arguments, CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Catch any exception inside the invocation
|
||||||
catch (TargetInvocationException e)
|
catch (TargetInvocationException e)
|
||||||
{
|
{
|
||||||
if (e.InnerException != null) throw e.InnerException;
|
if (e.InnerException != null) throw e.InnerException;
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes.ScriptFunction
|
namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
|
@ -19,7 +20,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
EvaluationScope = evaluationScope;
|
EvaluationScope = evaluationScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope)
|
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
||||||
{
|
{
|
||||||
var innerEvaluator = new Evaluator.Evaluator(diagnostics, EvaluationScope, script);
|
var innerEvaluator = new Evaluator.Evaluator(diagnostics, EvaluationScope, script);
|
||||||
for (var i = 0; i < Parameters.Length; i++)
|
for (var i = 0; i < Parameters.Length; i++)
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
|
|
||||||
foreach (var match in matches)
|
foreach (var match in matches)
|
||||||
{
|
{
|
||||||
if (IsValidMatch(match, ref args))
|
if (IsValidMatch(match, args.Select(x => x.GetType()).ToArray()))
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,27 +33,26 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValidMatch(MethodBase match, ref object[] args)
|
public bool IsValidMatch(MethodBase match, System.Type[] argumentTypes)
|
||||||
{
|
{
|
||||||
var parameters = match.GetParameters();
|
var parameters = match.GetParameters();
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
var matchParameter = parameters[i];
|
var matchParameter = parameters[i];
|
||||||
if (args.Length <= i)
|
if (argumentTypes.Length <= i)
|
||||||
{
|
{
|
||||||
if (matchParameter.IsOptional)
|
if (matchParameter.IsOptional)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var argument = args[i];
|
var argumentType = argumentTypes[i];
|
||||||
var argumentType = argument.GetType();
|
|
||||||
|
|
||||||
var typeCode = System.Type.GetTypeCode(matchParameter.ParameterType);
|
var typeCode = System.Type.GetTypeCode(matchParameter.ParameterType);
|
||||||
switch (typeCode)
|
switch (typeCode)
|
||||||
{
|
{
|
||||||
case TypeCode.Boolean:
|
case TypeCode.Boolean:
|
||||||
if (argument is ScriptBoolean)
|
if (argumentType == typeof(ScriptBoolean))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +60,7 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
break;
|
break;
|
||||||
case TypeCode.Char:
|
case TypeCode.Char:
|
||||||
case TypeCode.String:
|
case TypeCode.String:
|
||||||
if (argument is ScriptString)
|
if (argumentType == typeof(ScriptString))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +77,7 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
case TypeCode.UInt16:
|
case TypeCode.UInt16:
|
||||||
case TypeCode.UInt32:
|
case TypeCode.UInt32:
|
||||||
case TypeCode.UInt64:
|
case TypeCode.UInt64:
|
||||||
if (argument is ScriptNumber)
|
if (typeof(ScriptNumber).IsAssignableFrom(argumentType))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -88,14 +87,6 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
continue;
|
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))
|
if (argumentType == typeof(ScriptNull))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -195,7 +186,20 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
if (typeof(IList).IsAssignableFrom(type))
|
if (typeof(IList).IsAssignableFrom(type))
|
||||||
{
|
{
|
||||||
if (value is ListUserData d)
|
if (value is ListUserData d)
|
||||||
return d.List;
|
{
|
||||||
|
if (d.List.GetType() == type)
|
||||||
|
return d.List;
|
||||||
|
|
||||||
|
var generics = type.GetGenericArguments();
|
||||||
|
var l1 = typeof(List<>);
|
||||||
|
var requiredListType = l1.MakeGenericType(generics[0]);
|
||||||
|
var list = (IList)Activator.CreateInstance(requiredListType);
|
||||||
|
foreach (var variable in d.List)
|
||||||
|
{
|
||||||
|
list.Add(ChangeType(variable, requiredListType, culture));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
if (value is ScriptTable.ScriptTable table)
|
if (value is ScriptTable.ScriptTable table)
|
||||||
{
|
{
|
||||||
var generics = type.GetGenericArguments();
|
var generics = type.GetGenericArguments();
|
||||||
|
@ -262,8 +266,15 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
|
|
||||||
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] matches, System.Type[] types, ParameterModifier[] modifiers)
|
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] matches, System.Type[] types, ParameterModifier[] modifiers)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
foreach (var match in matches)
|
||||||
|
{
|
||||||
|
if (IsValidMatch(match, types))
|
||||||
|
{
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, System.Type returnType, System.Type[] indexes,
|
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, System.Type returnType, System.Type[] indexes,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.StandardLibraries;
|
using Upsilon.StandardLibraries;
|
||||||
|
@ -78,7 +79,7 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
foreach (var userDataMethodPart in MethodParts)
|
foreach (var userDataMethodPart in MethodParts)
|
||||||
{
|
{
|
||||||
var methodBase = userDataMethodPart.Method;
|
var methodBase = userDataMethodPart.Method;
|
||||||
if (UpsilonBinder.Default.IsValidMatch(methodBase, ref arguments))
|
if (UpsilonBinder.Default.IsValidMatch(methodBase, arguments.Select(x => x.GetType()).ToArray()))
|
||||||
{
|
{
|
||||||
var parameters = methodBase.GetParameters();
|
var parameters = methodBase.GetParameters();
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
|
|
|
@ -538,7 +538,7 @@ namespace Upsilon.Evaluator
|
||||||
ls.Add(evaluate);
|
ls.Add(evaluate);
|
||||||
}
|
}
|
||||||
|
|
||||||
var val = function.Run(_diagnostics, ls.ToArray(), _script, Scope);
|
var val = function.Run(_diagnostics, ls.ToArray(), _script, Scope, boundFunctionCallExpression.Span);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue