Work on calling CSharp methods

This commit is contained in:
Deukhoofd 2018-12-11 15:50:24 +01:00
parent efea92d32a
commit e57129e116
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
6 changed files with 100 additions and 25 deletions

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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++)

View File

@ -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,

View File

@ -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++)

View File

@ -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;
} }