Allows for overloaded functions in CSharp to be used, initial work on handling CSHarp operators

This commit is contained in:
Deukhoofd 2018-11-21 13:08:41 +01:00
parent fe4a8d25ad
commit 0702b9f271
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
15 changed files with 257 additions and 6 deletions

View File

@ -13,6 +13,11 @@ namespace Upsilon.BaseTypes
return Value;
}
public override System.Type GetCSharpType()
{
return typeof(bool);
}
public bool Value { get; }
public static implicit operator bool(LuaBoolean b)

View File

@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Upsilon.BaseTypes.UserData;
using Upsilon.Binder;
using Upsilon.Evaluator;
@ -14,6 +15,11 @@ namespace Upsilon.BaseTypes
return this;
}
public override System.Type GetCSharpType()
{
return null;
}
public abstract LuaType Run(Diagnostics diagnostics, LuaType[] variables);
}
@ -46,19 +52,21 @@ namespace Upsilon.BaseTypes
internal class LuaMethodInfoFunction : LuaFunction
{
public LuaMethodInfoFunction(MethodInfo method, object o)
public LuaMethodInfoFunction(UserDataMethod method, object o)
{
_method = method;
_object = o;
}
private readonly MethodInfo _method;
private readonly UserDataMethod _method;
private readonly object _object;
public override LuaType Run(Diagnostics diagnostics, LuaType[] variables)
{
var types = variables.Select(x => x.GetCSharpType());
var method = _method.GetMethod(types.ToArray());
var objects = variables.Select(x => x.ToCSharpObject());
return _method.Invoke(_object, objects.ToArray()).ToLuaType();
return method.Invoke(_object, objects.ToArray()).ToLuaType();
}
}
}

View File

@ -8,6 +8,11 @@ namespace Upsilon.BaseTypes
return null;
}
public override System.Type GetCSharpType()
{
return null;
}
public override string ToString()
{
return "null";

View File

@ -19,6 +19,11 @@ namespace Upsilon.BaseTypes
return Value;
}
public override System.Type GetCSharpType()
{
return typeof(string);
}
public override bool Equals(object obj)
{
if (obj == null)

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Upsilon.Binder;
using Upsilon.Evaluator;
@ -21,6 +22,11 @@ namespace Upsilon.BaseTypes
return EvaluationScope.Variables.ToDictionary(x => x.Key, x => x.Value.ToCSharpObject());
}
public override System.Type GetCSharpType()
{
return typeof(Dictionary<string, object>);
}
public LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope)
{
if (EvaluationScope.TryGet(s, out var o))

View File

@ -4,5 +4,6 @@ namespace Upsilon.BaseTypes
{
public abstract Type Type { get; }
public abstract object ToCSharpObject();
public abstract System.Type GetCSharpType();
}
}

View File

@ -31,5 +31,10 @@ namespace Upsilon.BaseTypes.Number
{
return Value;
}
public override System.Type GetCSharpType()
{
return typeof(double);
}
}
}

View File

@ -34,5 +34,10 @@ namespace Upsilon.BaseTypes.Number
{
return Value;
}
public override System.Type GetCSharpType()
{
return typeof(long);
}
}
}

View File

@ -20,6 +20,11 @@ namespace Upsilon.BaseTypes.UserData
return Value;
}
public override System.Type GetCSharpType()
{
return Value.GetType();
}
public LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope)
{
var (type, failed) = _typeInfo.Get(Value, s);

View File

@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Upsilon.BaseTypes.UserData
{
public class UserDataMethod
{
private class UserDataMethodPart
{
public UserDataMethodPart(MethodInfo method)
{
Method = method;
Parameters = method.GetParameters().Select(x => new UserDataMethodParameter(x)).ToArray();
}
public MethodInfo Method { get; }
public UserDataMethodParameter[] Parameters { get; }
}
private struct UserDataMethodParameter
{
public UserDataMethodParameter(ParameterInfo info)
{
TypeHash = info.ParameterType.GetHashCode();
IsOptional = info.IsOptional;
}
public int TypeHash { get; }
public bool IsOptional { get; }
}
private List<UserDataMethodPart> MethodParts { get; }
public UserDataMethod(MethodInfo method)
{
var part = new UserDataMethodPart(method);
MethodParts = new List<UserDataMethodPart>()
{
part
};
}
public void LoadMethodPart(MethodInfo method)
{
var part = new UserDataMethodPart(method);
MethodParts.Add(part);
}
public MethodInfo GetMethod(System.Type[] parameterTypes)
{
foreach (var userDataMethodPart in MethodParts)
{
bool valid = true;
for (var index = 0; index < userDataMethodPart.Parameters.Length; index++)
{
var userDataMethodParameter = userDataMethodPart.Parameters[index];
if (index >= parameterTypes.Length)
{
if (userDataMethodParameter.IsOptional)
return userDataMethodPart.Method;
valid = false;
break;
}
var parameterHash = parameterTypes[index].GetHashCode();
if (userDataMethodParameter.TypeHash != parameterHash)
{
valid = false;
break;
}
}
if (valid) return userDataMethodPart.Method;
}
return null;
}
}
}

View File

@ -0,0 +1,22 @@
using System.Linq;
namespace Upsilon.BaseTypes.UserData
{
public struct UserDataMethodKey
{
public UserDataMethodKey(string name, System.Type[] parameterTypes)
{
Name = name;
ParameterTypeHashes = parameterTypes.Select(x => x.GetHashCode()).ToArray();
}
public UserDataMethodKey(string name, int[] parameterTypeHashes)
{
Name = name;
ParameterTypeHashes = parameterTypeHashes;
}
public string Name { get; }
public int[] ParameterTypeHashes { get; }
}
}

View File

@ -11,13 +11,27 @@ namespace Upsilon.BaseTypes.UserData
Type = type;
Variables = type.GetFields().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
Properties = type.GetProperties().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
Methods = type.GetMethods().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
Methods = new Dictionary<string, UserDataMethod>();
foreach (var methodInfo in type.GetMethods())
{
var commonName = methodInfo.Name.ToLowerInvariant();
if (Methods.TryGetValue(commonName, out var methodData))
{
methodData.LoadMethodPart(methodInfo);
}
else
{
Methods.Add(commonName, new UserDataMethod(methodInfo));
}
}
_operatorHandler = new UserDataTypeOperators(type);
}
private System.Type Type { get; }
private Dictionary<string, FieldInfo> Variables { get; }
private Dictionary<string, PropertyInfo> Properties { get; }
private Dictionary<string, MethodInfo> Methods { get; }
private Dictionary<string, UserDataMethod> Methods { get; }
private UserDataTypeOperators _operatorHandler { get; }
public (LuaType Type, bool Failed) Get(object value, string member)
{
@ -57,5 +71,10 @@ namespace Upsilon.BaseTypes.UserData
return true;
}
public (LuaType Type, bool Failed) BinaryOperator(object value, OperatorType op, object value2)
{
return (null, true);
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Reflection;
namespace Upsilon.BaseTypes.UserData
{
public enum OperatorType
{
Addition,
}
public class UserDataTypeOperators
{
private class OperatorKeyData
{
}
public UserDataTypeOperators(System.Type t)
{
var additionMethod = t.GetMethod("op_Addition", BindingFlags.Static | BindingFlags.Public);
Console.WriteLine(additionMethod);
}
}
}

View File

@ -1,4 +1,3 @@
using System;
using Upsilon.Evaluator;
using Xunit;

View File

@ -0,0 +1,63 @@
using System;
using Upsilon.BaseTypes.UserData;
using Upsilon.Evaluator;
using Xunit;
// ReSharper disable UnusedMember.Local
// ReSharper disable ClassNeverInstantiated.Global
namespace UpsilonTests
{
public class UserDataOperatorTests : IClassFixture<UserDataOperatorTests.UserDataOperatorTestsFixture>
{
public class UserDataOperatorTestsFixture : IDisposable
{
public UserDataOperatorTestsFixture()
{
UserDataTypeHandler.LoadType<UserDataHelper>();
}
public void Dispose()
{
}
}
#pragma warning disable 414, 649
private class UserDataHelper
{
public UserDataHelper(double value)
{
Value = value;
}
public double Value { get; }
public static UserDataHelper operator +(UserDataHelper a, UserDataHelper b)
{
return new UserDataHelper(a.Value + b.Value);
}
public static UserDataHelper operator +(UserDataHelper a, double b)
{
return new UserDataHelper(a.Value + b);
}
}
#pragma warning restore 414, 649
[Fact]
public void TestAddition()
{
const string input = @"
function add(o1, o2)
return o1 + o2
end
";
var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages);
var o1 = new UserDataHelper(100);
var o2 = new UserDataHelper(215);
var result = script.EvaluateFunction("add", new[] {o1, o2});
}
}
}