Implement function overloading

This commit is contained in:
Deukhoofd 2019-09-14 11:10:40 +02:00
parent 1b32ab921b
commit 1c181442e8
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
4 changed files with 93 additions and 38 deletions

View File

@ -121,17 +121,35 @@ namespace PorygonSharp.UserData
private void RegisterFunction(MethodInfo method)
{
var type = ScriptType.ScriptTypeHandler.GetFunctionScriptType(method);
if (type == IntPtr.Zero || !type.HasValue)
return;
var fieldName = method.Name.ScriptHash();
if (Fields.ContainsKey(fieldName))
return;
var fieldData = new UserDataField(method);
var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero);
if (Fields.TryGetValue(fieldName, out var f))
{
if (!(f is UserDataFunctionField func))
return;
var methodPtr = func.MethodPtr;
var ret = ScriptType.ScriptTypeHandler.GetScriptType(method.ReturnType);
if (!ret.HasValue) return;
var parameters = method.GetParameters()
.Select(x => ScriptType.ScriptTypeHandler.GetScriptType(x.ParameterType))
.ToArray();
if (parameters.Any(x => !x.HasValue))
return;
RegisterUserDataFunctionScriptTypeOption(methodPtr, ret.Value,
parameters.Select(x => x.Value).ToArray(), parameters.Length);
func.RegisterOption(method);
}
else
{
var type = ScriptType.ScriptTypeHandler.GetFunctionScriptType(method);
if (type == IntPtr.Zero || !type.HasValue)
return;
var fieldData = new UserDataFunctionField(method, type.Value);
var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero);
RegisterUserDataField(Id, fieldName, userDataField);
Fields.Add(fieldName, fieldData);
}
RegisterUserDataField(Id, fieldName, userDataField);
Fields.Add(fieldName, fieldData);
}
private bool IsCastable(IntPtr scriptTypePtr, bool isExplicit)
@ -236,6 +254,9 @@ namespace PorygonSharp.UserData
[DllImport("PorygonLang", EntryPoint = "AddUserdataBinaryOperation", CallingConvention = CallingConvention.Cdecl)]
private static extern void AddUserdataBinaryOperation(uint id, byte kind, IntPtr operation);
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataFunctionScriptTypeOption", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr RegisterUserDataFunctionScriptTypeOption(IntPtr existing, IntPtr returnType,
IntPtr[] parameters, int parameterCount);
}
}

View File

@ -1,9 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
namespace PorygonSharp.UserData
{
@ -11,11 +9,11 @@ namespace PorygonSharp.UserData
{
internal delegate IntPtr GetterDelegate(IntPtr ptr);
internal delegate void SetterDelegate(IntPtr ptr, IntPtr val);
private delegate IntPtr CallerDelegate(IntPtr parent, IntPtr scriptOption,
protected delegate IntPtr CallerDelegate(IntPtr parent, IntPtr scriptOption,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]IntPtr[] parameters, int size);
private readonly GetterDelegate _getter;
private readonly SetterDelegate _setter;
protected GetterDelegate _getter;
protected readonly SetterDelegate _setter;
public UserDataField(FieldInfo field)
{
@ -58,30 +56,8 @@ namespace PorygonSharp.UserData
};
}
}
public UserDataField(MethodInfo method)
{
var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
_getter = ptr =>
{
var func = new CallerDelegate((parent, scriptOptions, parameters, size) =>
{
var evaluatedParameters = new object[size];
for (var i = 0; i < size; i++)
{
var eval = new EvalValue(parameters[i]);
evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]);
}
var parentObj = GCHandle.FromIntPtr(parent).Target;
var result = method.Invoke(parentObj, evaluatedParameters);
return EvalValueCreator.CreateValue(result).GetPointer();
});
var funcPtr = Marshal.GetFunctionPointerForDelegate(func);
return EvalValueCreator.FunctionEvalValue(funcPtr, ptr).GetPointer();
};
}
protected UserDataField(){}
public UserDataField(GetterDelegate getter, SetterDelegate setter)
{

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
namespace PorygonSharp.UserData
{
internal class UserDataFunctionField : UserDataField
{
public readonly IntPtr MethodPtr;
private readonly List<CallerDelegate> _callers;
public UserDataFunctionField(MethodInfo method, IntPtr methodPtr)
{
_getter = ptr =>
{
var funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[0]);
var val = EvalValueCreator.FunctionEvalValue(funcPtr, ptr);
for (var i = 1; i < _callers.Count; i++)
{
funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[i]);
RegisterFunctionEvalValueOption(val.GetPointer(), funcPtr, ptr);
}
return val.GetPointer();
};
MethodPtr = methodPtr;
_callers = new List<CallerDelegate>(){CreateCaller(method)};
}
private CallerDelegate CreateCaller(MethodInfo method)
{
var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
return (parent, scriptOptions, parameters, size) =>
{
var evaluatedParameters = new object[size];
for (var i = 0; i < size; i++)
{
var eval = new EvalValue(parameters[i]);
evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]);
}
var parentObj = GCHandle.FromIntPtr(parent).Target;
var result = method.Invoke(parentObj, evaluatedParameters);
return EvalValueCreator.CreateValue(result).GetPointer();
};
}
internal void RegisterOption(MethodInfo method)
{
_callers.Add(CreateCaller(method));
}
[DllImport("PorygonLang", EntryPoint = "RegisterFunctionEvalValueOption",CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr RegisterFunctionEvalValueOption(IntPtr val, IntPtr func, IntPtr obj);
}
}

Binary file not shown.