Support for turning delegates into script functions

This commit is contained in:
Deukhoofd 2019-09-12 20:23:25 +02:00
parent 6402746101
commit 8d16c1fb35
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 99 additions and 32 deletions

View File

@ -0,0 +1,41 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using PorygonSharp.Utilities;
namespace PorygonSharp.EvalValues
{
public class DelegateEvalValue
{
private delegate IntPtr InvokeDelegate(IntPtr _, IntPtr options,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]IntPtr[] parameters, int parameterCount);
private readonly Delegate _delegate;
private readonly InvokeDelegate _handler;
public readonly IntPtr Pointer;
public DelegateEvalValue(Delegate del)
{
_delegate = del;
_handler = Invoke;
var funcPtr = Marshal.GetFunctionPointerForDelegate(_handler);
Pointer = EvalValueCreator.CreateFunctionEvalValue(funcPtr, IntPtr.Zero);
}
private IntPtr Invoke(IntPtr _, IntPtr options, IntPtr[] parPtrs, int parameterCount)
{
var parameters = new object[parameterCount];
var parametersTypes = _delegate.Method.GetParameters().Select(x => x.ParameterType).ToArray();
for (var i = 0; i < parameterCount; i++)
{
var val = new EvalValue(parPtrs[i]);
parameters[i] = Caster.Cast(val, parametersTypes[i]);
}
var result = _delegate.DynamicInvoke(parameters);
return EvalValueCreator.CreateValue(result).GetPointer();
}
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using PorygonSharp.UserData;
@ -43,6 +42,10 @@ namespace PorygonSharp.EvalValues
case TypeCode.Object:
if (typeof(IList).IsAssignableFrom(type))
return CreateListEvalValue((IList)o, type);
if (typeof(Delegate).IsAssignableFrom(type))
{
return CreateDelegateEvalValue((Delegate) o);
}
if (!UserDataHandler.IsTypeRegistered(type) && !UserDataHandler.TryResolveType(type))
{
throw new Exception($"Type is not registered for use: {type.FullName}");
@ -68,8 +71,14 @@ namespace PorygonSharp.EvalValues
return new EvalValue(ptr);
}
private static EvalValue CreateDelegateEvalValue(Delegate del)
{
var val = new DelegateEvalValue(del);
return new EvalValue(val.Pointer);
}
[DllImport("PorygonLang", EntryPoint = "CreateNilEvalValue",CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr CreateNilEvalValue();
private static extern IntPtr CreateNilEvalValue();
[DllImport("PorygonLang", EntryPoint = "CreateIntegerEvalValue",CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr CreateIntegerEvalValue(long l);
[DllImport("PorygonLang", EntryPoint = "CreateFloatEvalValue",CallingConvention = CallingConvention.Cdecl)]
@ -82,7 +91,7 @@ namespace PorygonSharp.EvalValues
private static extern IntPtr CreateUserDataEvalValue(uint typeHash, IntPtr obj);
[DllImport("PorygonLang", EntryPoint = "CreateFunctionEvalValue",CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateFunctionEvalValue(IntPtr func, IntPtr parent);
internal static extern IntPtr CreateFunctionEvalValue(IntPtr func, IntPtr parent);
[DllImport("PorygonLang", EntryPoint = "CreateCollectionValue", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateCollectionValue(IntPtr type, IntPtr parent, IntPtr getter, IntPtr setter,

View File

@ -10,6 +10,10 @@ namespace PorygonSharp.ScriptType
{
internal static IntPtr? GetScriptType(Type t)
{
if (t == null)
{
return CreateScriptType(TypeClass.Nil);
}
if (t.IsEnum && !t.IsGenericParameter)
{
if (UserDataHandler.IsTypeRegistered(t))
@ -42,6 +46,10 @@ namespace PorygonSharp.ScriptType
{
return CreateScriptType(TypeClass.Nil);
}
if (t == typeof(object))
{
return CreateScriptType(TypeClass.Any);
}
if (UserDataHandler.IsTypeRegistered(t))
{
return UserDataHandler.CreateUserDataType(t);
@ -55,6 +63,11 @@ namespace PorygonSharp.ScriptType
return CreateUserDataDictionaryType(t);
}
if (typeof(Delegate).IsAssignableFrom(t))
{
return GetFunctionScriptType(t.GetMethod("Invoke"));
}
var attr = t.GetCustomAttribute<Attributes.PorygonUserdataAttribute>();
if (attr != null)
{

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
@ -7,14 +8,16 @@ namespace PorygonSharp
{
public static class StaticScope
{
private static List<object> _variables = new List<object>();
public static void RegisterStaticVariable(string name, object o)
{
var type = o.GetType();
var scriptType = ScriptType.ScriptTypeHandler.GetScriptType(type);
var hash = name.ScriptHash();
var value = EvalValueCreator.CreateValue(o);
if (!scriptType.HasValue)
return;
var hash = name.ScriptHash();
var value = EvalValueCreator.CreateValue(o);
_variables.Add(o);
RegisterStaticVariable(hash, scriptType.Value, value.GetPointer());
}

View File

@ -10,5 +10,6 @@ namespace PorygonSharp
Function,
UserData,
Table,
Any
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Reflection;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
namespace PorygonSharp.UserData
{
@ -38,17 +39,7 @@ namespace PorygonSharp.UserData
{
var a = GCHandle.FromIntPtr(objectPtr).Target;
var b = new EvalValue(variable);
var bVal = b.GetObjectValue();
if (_parameterType.IsEnum)
{
var baseType = _parameterType.GetEnumUnderlyingType();
bVal = Convert.ChangeType(bVal, baseType);
}
else if (bVal is IConvertible)
{
var convertedType = Convert.ChangeType(bVal, _parameterType);
bVal = convertedType;
}
var bVal = Caster.Cast(b, _parameterType);
var o = _info.Invoke(null, new[] {a, bVal});
return EvalValueCreator.CreateValue(o).GetPointer();
}

View File

@ -3,6 +3,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
namespace PorygonSharp.UserData
{
@ -70,22 +71,7 @@ namespace PorygonSharp.UserData
for (var i = 0; i < size; i++)
{
var eval = new EvalValue(parameters[i]);
var val = eval.GetObjectValue();
var desiredType = parameterTypes[i];
if (desiredType.IsEnum)
{
var baseType = desiredType.GetEnumUnderlyingType();
evaluatedParameters[i] = Convert.ChangeType(val, baseType);
}
else if (val is IConvertible)
{
var convertedType = Convert.ChangeType(val, desiredType);
evaluatedParameters[i] = convertedType;
}
else
{
evaluatedParameters[i] = val;
}
evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]);
}
var parentObj = GCHandle.FromIntPtr(parent).Target;

View File

@ -0,0 +1,23 @@
using System;
using PorygonSharp.EvalValues;
namespace PorygonSharp.Utilities
{
public static class Caster
{
public static object Cast(EvalValue val, Type t)
{
var eval = val.GetObjectValue();
if (t.IsEnum)
{
var underlying = t.GetEnumUnderlyingType();
return Convert.ChangeType(eval, underlying);
}
if (eval is IConvertible)
{
return Convert.ChangeType(eval, t);
}
return eval;
}
}
}