Support for calling userdata functions
This commit is contained in:
parent
0ff2815694
commit
f23f682d52
|
@ -13,15 +13,14 @@ namespace PorygonSharp
|
||||||
_handle = handle;
|
_handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EvalValue(object o)
|
public static EvalValue CreateValue(object o)
|
||||||
{
|
{
|
||||||
var type = o.GetType();
|
var type = o.GetType();
|
||||||
var typeCode = Type.GetTypeCode(type);
|
var typeCode = Type.GetTypeCode(type);
|
||||||
switch (typeCode)
|
switch (typeCode)
|
||||||
{
|
{
|
||||||
case TypeCode.Boolean:
|
case TypeCode.Boolean:
|
||||||
_handle = CreateBoolEvalValue((bool)o);
|
return new EvalValue(CreateBoolEvalValue((bool)o));
|
||||||
break;
|
|
||||||
case TypeCode.Byte:
|
case TypeCode.Byte:
|
||||||
case TypeCode.SByte:
|
case TypeCode.SByte:
|
||||||
case TypeCode.Int16:
|
case TypeCode.Int16:
|
||||||
|
@ -30,22 +29,18 @@ namespace PorygonSharp
|
||||||
case TypeCode.UInt16:
|
case TypeCode.UInt16:
|
||||||
case TypeCode.UInt32:
|
case TypeCode.UInt32:
|
||||||
case TypeCode.UInt64:
|
case TypeCode.UInt64:
|
||||||
_handle = CreateIntegerEvalValue(Convert.ToInt64(o));
|
return new EvalValue(CreateIntegerEvalValue(Convert.ToInt64(o)));
|
||||||
break;
|
|
||||||
case TypeCode.Char:
|
case TypeCode.Char:
|
||||||
case TypeCode.String:
|
case TypeCode.String:
|
||||||
_handle = CreateStringEvalValue(o.ToString());
|
return new EvalValue(CreateStringEvalValue(o.ToString()));
|
||||||
break;
|
|
||||||
case TypeCode.Decimal:
|
case TypeCode.Decimal:
|
||||||
case TypeCode.Double:
|
case TypeCode.Double:
|
||||||
case TypeCode.Single:
|
case TypeCode.Single:
|
||||||
_handle = CreateFloatEvalValue(Convert.ToDouble(o));
|
return new EvalValue(CreateFloatEvalValue(Convert.ToDouble(o)));
|
||||||
break;
|
|
||||||
case TypeCode.Object:
|
case TypeCode.Object:
|
||||||
var typeHash = UserDataHandler.GetTypeId(type);
|
var typeHash = UserDataHandler.GetTypeId(type);
|
||||||
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
|
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
|
||||||
_handle = CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle));
|
return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle)));
|
||||||
break;
|
|
||||||
case TypeCode.DateTime:
|
case TypeCode.DateTime:
|
||||||
case TypeCode.DBNull:
|
case TypeCode.DBNull:
|
||||||
case TypeCode.Empty:
|
case TypeCode.Empty:
|
||||||
|
@ -54,6 +49,12 @@ namespace PorygonSharp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EvalValue FunctionEvalValue(IntPtr func, IntPtr parent)
|
||||||
|
{
|
||||||
|
return new EvalValue(CreateFunctionEvalValue(func, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_handle != IntPtr.Zero)
|
if (_handle != IntPtr.Zero)
|
||||||
|
@ -89,6 +90,12 @@ namespace PorygonSharp
|
||||||
return Marshal.PtrToStringUni(ptr);
|
return Marshal.PtrToStringUni(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object EvaluateGenericObject()
|
||||||
|
{
|
||||||
|
var ptr = EvaluateUserDataObj(_handle);
|
||||||
|
return GCHandle.FromIntPtr(ptr).Target;
|
||||||
|
}
|
||||||
|
|
||||||
public object GetObjectValue()
|
public object GetObjectValue()
|
||||||
{
|
{
|
||||||
switch (GetTypeClass())
|
switch (GetTypeClass())
|
||||||
|
@ -101,8 +108,9 @@ namespace PorygonSharp
|
||||||
return EvaluateBool();
|
return EvaluateBool();
|
||||||
case TypeClass.String:
|
case TypeClass.String:
|
||||||
return EvaluateString();
|
return EvaluateString();
|
||||||
case TypeClass.Function:
|
|
||||||
case TypeClass.UserData:
|
case TypeClass.UserData:
|
||||||
|
return EvaluateGenericObject();
|
||||||
|
case TypeClass.Function:
|
||||||
case TypeClass.Table:
|
case TypeClass.Table:
|
||||||
case TypeClass.Error:
|
case TypeClass.Error:
|
||||||
default:
|
default:
|
||||||
|
@ -127,6 +135,8 @@ namespace PorygonSharp
|
||||||
private static extern bool EvaluateBool(IntPtr ptr);
|
private static extern bool EvaluateBool(IntPtr ptr);
|
||||||
[DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueString",CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueString",CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr EvaluateString(IntPtr ptr);
|
private static extern IntPtr EvaluateString(IntPtr ptr);
|
||||||
|
[DllImport("libPorygonLang", EntryPoint = "EvaluateUserDataObj",CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr EvaluateUserDataObj(IntPtr ptr);
|
||||||
|
|
||||||
[DllImport("libPorygonLang", EntryPoint = "CreateIntegerEvalValue",CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libPorygonLang", EntryPoint = "CreateIntegerEvalValue",CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr CreateIntegerEvalValue(long l);
|
private static extern IntPtr CreateIntegerEvalValue(long l);
|
||||||
|
@ -138,5 +148,9 @@ namespace PorygonSharp
|
||||||
private static extern IntPtr CreateStringEvalValue(string s);
|
private static extern IntPtr CreateStringEvalValue(string s);
|
||||||
[DllImport("libPorygonLang", EntryPoint = "CreateUserDataEvalValue",CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libPorygonLang", EntryPoint = "CreateUserDataEvalValue",CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr CreateUserDataEvalValue(uint typeHash, IntPtr obj);
|
private static extern IntPtr CreateUserDataEvalValue(uint typeHash, IntPtr obj);
|
||||||
|
|
||||||
|
[DllImport("libPorygonLang", EntryPoint = "CreateFunctionEvalValue",CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateFunctionEvalValue(IntPtr func, IntPtr parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -75,7 +75,7 @@ namespace PorygonSharp
|
||||||
|
|
||||||
public EvalValue CallFunction(string key, params object[] parameters)
|
public EvalValue CallFunction(string key, params object[] parameters)
|
||||||
{
|
{
|
||||||
var scriptParameters = parameters.Select(x => new EvalValue(x).GetPointer()).ToArray();
|
var scriptParameters = parameters.Select(x => EvalValue.CreateValue(x).GetPointer()).ToArray();
|
||||||
var ptr = CallFunction(_internalScriptHandle, key, scriptParameters, scriptParameters.Length);
|
var ptr = CallFunction(_internalScriptHandle, key, scriptParameters, scriptParameters.Length);
|
||||||
return new EvalValue(ptr);
|
return new EvalValue(ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace PorygonSharp.ScriptType
|
namespace PorygonSharp.ScriptType
|
||||||
|
@ -28,8 +29,35 @@ namespace PorygonSharp.ScriptType
|
||||||
case TypeCode.Char:
|
case TypeCode.Char:
|
||||||
case TypeCode.String:
|
case TypeCode.String:
|
||||||
return CreateStringScriptType(false, 0);
|
return CreateStringScriptType(false, 0);
|
||||||
|
case TypeCode.Object:
|
||||||
|
if (t == typeof(void))
|
||||||
|
{
|
||||||
|
return CreateScriptType(TypeClass.Nil);
|
||||||
|
}
|
||||||
|
goto default;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException(t.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IntPtr GetFunctionScriptType(MethodInfo info)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var returnType = GetScriptType(info.ReturnType);
|
||||||
|
var parameters = info.GetParameters();
|
||||||
|
var parameterFuncs = new IntPtr[parameters.Length];
|
||||||
|
for (var index = 0; index < parameters.Length; index++)
|
||||||
|
{
|
||||||
|
var parameter = parameters[index];
|
||||||
|
parameterFuncs[index] = GetScriptType(parameter.ParameterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateUserDataFunctionScriptType(returnType, parameterFuncs, parameters.Length);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,5 +70,7 @@ namespace PorygonSharp.ScriptType
|
||||||
[DllImport("libPorygonLang", EntryPoint = "CreateStringScriptType", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("libPorygonLang", EntryPoint = "CreateStringScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern IntPtr CreateStringScriptType(bool knownAtBind, uint hash);
|
private static extern IntPtr CreateStringScriptType(bool knownAtBind, uint hash);
|
||||||
|
|
||||||
|
[DllImport("libPorygonLang", EntryPoint = "CreateUserDataFunctionScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateUserDataFunctionScriptType(IntPtr returnType, IntPtr[] parameters, int parameterCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using PorygonSharp.Utilities;
|
using PorygonSharp.Utilities;
|
||||||
|
@ -12,6 +13,8 @@ namespace PorygonSharp.UserData
|
||||||
|
|
||||||
private delegate IntPtr GetterDelegate(IntPtr ptr);
|
private delegate IntPtr GetterDelegate(IntPtr ptr);
|
||||||
private delegate void SetterDelegate(IntPtr ptr, IntPtr val);
|
private delegate void SetterDelegate(IntPtr ptr, IntPtr val);
|
||||||
|
private delegate IntPtr CallerDelegate(IntPtr parent,
|
||||||
|
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]IntPtr[] parameters, int size);
|
||||||
|
|
||||||
public static void RegisterType(string name, Type type)
|
public static void RegisterType(string name, Type type)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +37,12 @@ namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
RegisterProperty(property, hash);
|
RegisterProperty(property, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var methods = type.GetMethods(bindingFlags);
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
RegisterFunction(method, hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterField(FieldInfo field, uint typeHash)
|
private static void RegisterField(FieldInfo field, uint typeHash)
|
||||||
|
@ -42,7 +51,7 @@ namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
var obj = GCHandle.FromIntPtr(ptr).Target;
|
var obj = GCHandle.FromIntPtr(ptr).Target;
|
||||||
var value = field.GetValue(obj);
|
var value = field.GetValue(obj);
|
||||||
return new EvalValue(value).GetPointer();
|
return EvalValue.CreateValue(value).GetPointer();
|
||||||
});
|
});
|
||||||
|
|
||||||
var setterPtr = IntPtr.Zero;
|
var setterPtr = IntPtr.Zero;
|
||||||
|
@ -73,7 +82,7 @@ namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
var obj = GCHandle.FromIntPtr(ptr).Target;
|
var obj = GCHandle.FromIntPtr(ptr).Target;
|
||||||
var value = property.GetValue(obj);
|
var value = property.GetValue(obj);
|
||||||
return new EvalValue(value).GetPointer();
|
return EvalValue.CreateValue(value).GetPointer();
|
||||||
});
|
});
|
||||||
getterPtr = Marshal.GetFunctionPointerForDelegate(getter);
|
getterPtr = Marshal.GetFunctionPointerForDelegate(getter);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +104,41 @@ namespace PorygonSharp.UserData
|
||||||
RegisterUserDataField(typeHash, fieldName, userDataField);
|
RegisterUserDataField(typeHash, fieldName, userDataField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void RegisterFunction(MethodInfo method, uint typeHash)
|
||||||
|
{
|
||||||
|
var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
|
||||||
|
|
||||||
|
var getter = new GetterDelegate(ptr =>
|
||||||
|
{
|
||||||
|
var func = new CallerDelegate((parent, parameters, size) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
var evaluatedParameters = new object[size];
|
||||||
|
for (var i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
var eval = new EvalValue(parameters[i]);
|
||||||
|
var val = eval.GetObjectValue();
|
||||||
|
var convertedType = Convert.ChangeType(val, parameterTypes[i]);
|
||||||
|
evaluatedParameters[i] = convertedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentObj = GCHandle.FromIntPtr(parent).Target;
|
||||||
|
var result = method.Invoke(parentObj, evaluatedParameters);
|
||||||
|
return EvalValue.CreateValue(result).GetPointer();
|
||||||
|
});
|
||||||
|
var funcPtr = Marshal.GetFunctionPointerForDelegate(func);
|
||||||
|
return EvalValue.FunctionEvalValue(funcPtr, ptr).GetPointer();
|
||||||
|
});
|
||||||
|
var getterPtr = Marshal.GetFunctionPointerForDelegate(getter);
|
||||||
|
var type = ScriptType.ScriptType.GetFunctionScriptType(method);
|
||||||
|
if (type == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
var userDataField = CreateUserDataField(type, getterPtr, IntPtr.Zero);
|
||||||
|
|
||||||
|
var fieldName = method.Name.ScriptHash();
|
||||||
|
RegisterUserDataField(typeHash, fieldName, userDataField);
|
||||||
|
}
|
||||||
|
|
||||||
public static uint GetTypeId(Type t)
|
public static uint GetTypeId(Type t)
|
||||||
{
|
{
|
||||||
return UserDataLookup[t];
|
return UserDataLookup[t];
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using PorygonSharp;
|
using PorygonSharp;
|
||||||
using PorygonSharp.UserData;
|
|
||||||
using PorygonSharp.Utilities;
|
using PorygonSharp.Utilities;
|
||||||
|
|
||||||
namespace PorygonSharpTests
|
namespace PorygonSharpTests
|
||||||
|
|
|
@ -15,6 +15,16 @@ namespace PorygonSharpTests
|
||||||
public int Bar { get; set; }
|
public int Bar { get; set; }
|
||||||
public int GetOnly { get; } = 865;
|
public int GetOnly { get; } = 865;
|
||||||
public readonly int ReadOnly = 684;
|
public readonly int ReadOnly = 684;
|
||||||
|
|
||||||
|
public int TestFunc()
|
||||||
|
{
|
||||||
|
return 345435;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Add(int a, int b)
|
||||||
|
{
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -146,5 +156,59 @@ end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CanCallUserdataFunction()
|
||||||
|
{
|
||||||
|
UserDataHandler.RegisterType("testObject", typeof(UserDataTestObject));
|
||||||
|
using (var script = new Script(@"
|
||||||
|
function test(testObject v)
|
||||||
|
result = v.TestFunc()
|
||||||
|
end
|
||||||
|
"))
|
||||||
|
{
|
||||||
|
var diags = script.Diagnostics.GetDiagnostics();
|
||||||
|
foreach (var diag in diags)
|
||||||
|
{
|
||||||
|
throw new Exception(script.Diagnostics.GetFullDiagnosticMessage(diag));
|
||||||
|
}
|
||||||
|
|
||||||
|
script.Evaluate();
|
||||||
|
|
||||||
|
var parameter = new UserDataTestObject();
|
||||||
|
|
||||||
|
script.CallFunction("test", parameter);
|
||||||
|
var variable = script.GetVariable("result");
|
||||||
|
Assert.AreEqual(TypeClass.Number ,variable.GetTypeClass());
|
||||||
|
Assert.AreEqual(345435, script.GetVariable("result").EvaluateInteger());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CanCallUserdataFunctionWithArguments()
|
||||||
|
{
|
||||||
|
UserDataHandler.RegisterType("testObject", typeof(UserDataTestObject));
|
||||||
|
using (var script = new Script(@"
|
||||||
|
function test(testObject v)
|
||||||
|
result = v.Add(5, 200)
|
||||||
|
end
|
||||||
|
"))
|
||||||
|
{
|
||||||
|
var diags = script.Diagnostics.GetDiagnostics();
|
||||||
|
foreach (var diag in diags)
|
||||||
|
{
|
||||||
|
throw new Exception(script.Diagnostics.GetFullDiagnosticMessage(diag));
|
||||||
|
}
|
||||||
|
|
||||||
|
script.Evaluate();
|
||||||
|
|
||||||
|
var parameter = new UserDataTestObject();
|
||||||
|
|
||||||
|
script.CallFunction("test", parameter);
|
||||||
|
var variable = script.GetVariable("result");
|
||||||
|
Assert.AreEqual(TypeClass.Number ,variable.GetTypeClass());
|
||||||
|
Assert.AreEqual(205, script.GetVariable("result").EvaluateInteger());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
Loading…
Reference in New Issue