Work on calling CSharp methods
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.ScriptFunction
|
||||
{
|
||||
@@ -15,6 +16,6 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||
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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Upsilon.BaseTypes.UserData;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Exceptions;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.ScriptFunction
|
||||
{
|
||||
@@ -42,7 +45,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||
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>();
|
||||
if (_passScriptReference)
|
||||
@@ -53,18 +56,76 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||
object result;
|
||||
try
|
||||
{
|
||||
// If no parent object for the function was given, this is likely a lambda function, these need to be static
|
||||
if (_object == null)
|
||||
{
|
||||
// grab the parameters, and just invoke it
|
||||
var array = objects.ToArray();
|
||||
var methodInfo = _method.GetMethod(ref array);
|
||||
result = methodInfo.Invoke(null, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, UpsilonBinder.Default,
|
||||
_object, objects.ToArray());
|
||||
// we create an array for the types of the objects
|
||||
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)
|
||||
{
|
||||
if (e.InnerException != null) throw e.InnerException;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.ScriptFunction
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||
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);
|
||||
for (var i = 0; i < Parameters.Length; i++)
|
||||
|
||||
Reference in New Issue
Block a user