Support for setting binary operations
This commit is contained in:
parent
8c3db0373b
commit
ae2080f145
|
@ -57,7 +57,7 @@ namespace PorygonSharp.EvalValues
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object EvaluateGenericObject()
|
private object EvaluateGenericObject()
|
||||||
{
|
{
|
||||||
var ptr = EvaluateUserDataObj(_handle);
|
var ptr = EvaluateUserDataObj(_handle);
|
||||||
return GCHandle.FromIntPtr(ptr).Target;
|
return GCHandle.FromIntPtr(ptr).Target;
|
||||||
|
|
|
@ -131,9 +131,11 @@ namespace PorygonSharp
|
||||||
public string GetBoundTreeString()
|
public string GetBoundTreeString()
|
||||||
{
|
{
|
||||||
var length = GetTreeStringLength(_internalScriptHandle);
|
var length = GetTreeStringLength(_internalScriptHandle);
|
||||||
var sb = new StringBuilder(length - 4);
|
var sb = new StringBuilder(length);
|
||||||
GetTreeString(_internalScriptHandle, sb);
|
GetTreeString(_internalScriptHandle, sb);
|
||||||
return sb.ToString();
|
var s = sb.ToString();
|
||||||
|
s = s.Substring(0, length);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("PorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
namespace PorygonSharp.UserData
|
||||||
|
{
|
||||||
|
internal enum BinaryOperationKind : byte
|
||||||
|
{
|
||||||
|
// Math
|
||||||
|
Addition,
|
||||||
|
Subtraction,
|
||||||
|
Multiplication,
|
||||||
|
Division,
|
||||||
|
|
||||||
|
// Equality
|
||||||
|
Equality,
|
||||||
|
Inequality,
|
||||||
|
Less,
|
||||||
|
LessOrEquals,
|
||||||
|
Greater,
|
||||||
|
GreaterOrEquals,
|
||||||
|
|
||||||
|
// Logical
|
||||||
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using PorygonSharp.EvalValues;
|
||||||
using PorygonSharp.Utilities;
|
using PorygonSharp.Utilities;
|
||||||
|
|
||||||
namespace PorygonSharp.UserData
|
namespace PorygonSharp.UserData
|
||||||
|
@ -43,6 +44,7 @@ namespace PorygonSharp.UserData
|
||||||
|
|
||||||
SetIsCastableFunc(id, Marshal.GetFunctionPointerForDelegate(_isCastableFunc));
|
SetIsCastableFunc(id, Marshal.GetFunctionPointerForDelegate(_isCastableFunc));
|
||||||
SetCastFunc(id, Marshal.GetFunctionPointerForDelegate(_castFunc));
|
SetCastFunc(id, Marshal.GetFunctionPointerForDelegate(_castFunc));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterFields()
|
internal void RegisterFields()
|
||||||
|
@ -79,6 +81,8 @@ namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
RegisterFunction(method);
|
RegisterFunction(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegisterOperations();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterField(FieldInfo field)
|
private void RegisterField(FieldInfo field)
|
||||||
|
@ -150,9 +154,9 @@ namespace PorygonSharp.UserData
|
||||||
var obj = GCHandle.FromIntPtr(objPtr).Target;
|
var obj = GCHandle.FromIntPtr(objPtr).Target;
|
||||||
var objType = obj.GetType();
|
var objType = obj.GetType();
|
||||||
if (expectedType.IsAssignableFrom(objType))
|
if (expectedType.IsAssignableFrom(objType))
|
||||||
return objPtr;
|
return EvalValueCreator.CreateValue(obj).GetPointer();
|
||||||
if (objType.IsAssignableFrom(expectedType))
|
if (objType.IsAssignableFrom(expectedType))
|
||||||
return objPtr;
|
return EvalValueCreator.CreateValue(obj).GetPointer();
|
||||||
if (_implicitCasts.TryGetValue(expectedType, out var func))
|
if (_implicitCasts.TryGetValue(expectedType, out var func))
|
||||||
{
|
{
|
||||||
var castVal = func.Invoke(null, new[] {obj});
|
var castVal = func.Invoke(null, new[] {obj});
|
||||||
|
@ -168,6 +172,54 @@ namespace PorygonSharp.UserData
|
||||||
throw new Exception("Invalid cast kind");
|
throw new Exception("Invalid cast kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterOperations()
|
||||||
|
{
|
||||||
|
var methods = Type.GetMethods(BindingFlags.Public | BindingFlags.Static);
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
switch (method.Name)
|
||||||
|
{
|
||||||
|
case "op_Addition":
|
||||||
|
RegisterOperation(BinaryOperationKind.Addition, method);
|
||||||
|
break;
|
||||||
|
case "op_Subtraction":
|
||||||
|
RegisterOperation(BinaryOperationKind.Subtraction, method);
|
||||||
|
break;
|
||||||
|
case "op_Multiply":
|
||||||
|
RegisterOperation(BinaryOperationKind.Multiplication, method);
|
||||||
|
break;
|
||||||
|
case "op_Division":
|
||||||
|
RegisterOperation(BinaryOperationKind.Division, method);
|
||||||
|
break;
|
||||||
|
case "op_Equality":
|
||||||
|
RegisterOperation(BinaryOperationKind.Equality, method);
|
||||||
|
break;
|
||||||
|
case "op_Inequality":
|
||||||
|
RegisterOperation(BinaryOperationKind.Inequality, method);
|
||||||
|
break;
|
||||||
|
case "op_LessThan":
|
||||||
|
RegisterOperation(BinaryOperationKind.Less, method);
|
||||||
|
break;
|
||||||
|
case "op_GreaterThan":
|
||||||
|
RegisterOperation(BinaryOperationKind.Greater, method);
|
||||||
|
break;
|
||||||
|
case "op_LessThanOrEqual":
|
||||||
|
RegisterOperation(BinaryOperationKind.LessOrEquals, method);
|
||||||
|
break;
|
||||||
|
case "op_GreaterThanOrEqual":
|
||||||
|
RegisterOperation(BinaryOperationKind.GreaterOrEquals, method);
|
||||||
|
break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterOperation(BinaryOperationKind kind, MethodInfo info)
|
||||||
|
{
|
||||||
|
var operation = UserDataBinaryOperation.Create(info);
|
||||||
|
AddUserdataBinaryOperation(Id, (byte)kind, operation.Handle);
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
||||||
internal static extern void RegisterUserDataField(uint hashId, uint fieldId, IntPtr field);
|
internal static extern void RegisterUserDataField(uint hashId, uint fieldId, IntPtr field);
|
||||||
|
|
||||||
|
@ -180,5 +232,9 @@ namespace PorygonSharp.UserData
|
||||||
[DllImport("PorygonLang", EntryPoint = "SetCastFunc", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("PorygonLang", EntryPoint = "SetCastFunc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void SetCastFunc(uint id, IntPtr castFunc);
|
private static extern void SetCastFunc(uint id, IntPtr castFunc);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "AddUserdataBinaryOperation", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void AddUserdataBinaryOperation(uint id, byte kind, IntPtr operation);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using PorygonSharp.EvalValues;
|
||||||
|
|
||||||
|
namespace PorygonSharp.UserData
|
||||||
|
{
|
||||||
|
public class UserDataBinaryOperation
|
||||||
|
{
|
||||||
|
private delegate IntPtr BinaryFunctionDelegate(IntPtr objectPtr, IntPtr variable);
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
private readonly BinaryFunctionDelegate _func;
|
||||||
|
private readonly MethodInfo _info;
|
||||||
|
private readonly Type _parameterType;
|
||||||
|
internal IntPtr Handle { get; private set; }
|
||||||
|
private UserDataBinaryOperation(MethodInfo info)
|
||||||
|
{
|
||||||
|
_info = info;
|
||||||
|
_func = Invoke;
|
||||||
|
_parameterType = info.GetParameters()[1].ParameterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserDataBinaryOperation Create(MethodInfo info)
|
||||||
|
{
|
||||||
|
var op = new UserDataBinaryOperation(info);
|
||||||
|
var funcPtr = Marshal.GetFunctionPointerForDelegate(op._func);
|
||||||
|
var secParType = ScriptType.ScriptTypeHandler.GetScriptType(op._parameterType);
|
||||||
|
var returnType = ScriptType.ScriptTypeHandler.GetScriptType(op._info.ReturnType);
|
||||||
|
if (!secParType.HasValue || !returnType.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
op.Handle = CreateUserdataBinaryOperation(funcPtr, secParType.Value, returnType.Value);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr Invoke(IntPtr objectPtr, IntPtr variable)
|
||||||
|
{
|
||||||
|
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 o = _info.Invoke(null, new[] {a, bVal});
|
||||||
|
return EvalValueCreator.CreateValue(o).GetPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateUserdataBinaryOperation", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateUserdataBinaryOperation(IntPtr func, IntPtr secondParameterType, IntPtr returnType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,7 +72,12 @@ namespace PorygonSharp.UserData
|
||||||
var eval = new EvalValue(parameters[i]);
|
var eval = new EvalValue(parameters[i]);
|
||||||
var val = eval.GetObjectValue();
|
var val = eval.GetObjectValue();
|
||||||
var desiredType = parameterTypes[i];
|
var desiredType = parameterTypes[i];
|
||||||
if (val is IConvertible)
|
if (desiredType.IsEnum)
|
||||||
|
{
|
||||||
|
var baseType = desiredType.GetEnumUnderlyingType();
|
||||||
|
evaluatedParameters[i] = Convert.ChangeType(val, baseType);
|
||||||
|
}
|
||||||
|
else if (val is IConvertible)
|
||||||
{
|
{
|
||||||
var convertedType = Convert.ChangeType(val, desiredType);
|
var convertedType = Convert.ChangeType(val, desiredType);
|
||||||
evaluatedParameters[i] = convertedType;
|
evaluatedParameters[i] = convertedType;
|
||||||
|
|
Binary file not shown.
|
@ -27,6 +27,18 @@ namespace PorygonSharpTests
|
||||||
{
|
{
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UserDataTestObject operator + (UserDataTestObject a, UserDataTestObject b)
|
||||||
|
{
|
||||||
|
a.Foo += b.Foo;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserDataTestObject operator + (UserDataTestObject a, int b)
|
||||||
|
{
|
||||||
|
a.Foo += b;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -311,5 +323,53 @@ end
|
||||||
Assert.AreEqual(347807, result.EvaluateInteger());
|
Assert.AreEqual(347807, result.EvaluateInteger());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CanUseBinaryOperations()
|
||||||
|
{
|
||||||
|
UserDataHandler.RegisterType("testObject", typeof(UserDataTestObject));
|
||||||
|
using (var script = new Script(@"
|
||||||
|
function test(testObject a, testObject b)
|
||||||
|
return a + b
|
||||||
|
end
|
||||||
|
"))
|
||||||
|
{
|
||||||
|
var diags = script.Diagnostics.GetDiagnostics();
|
||||||
|
foreach (var diag in diags)
|
||||||
|
{
|
||||||
|
throw new Exception(script.Diagnostics.GetFullDiagnosticMessage(diag));
|
||||||
|
}
|
||||||
|
|
||||||
|
script.Evaluate();
|
||||||
|
var a = new UserDataTestObject();
|
||||||
|
var b = new UserDataTestObject();
|
||||||
|
var result = script.CallFunction("test", a, b);
|
||||||
|
Assert.AreEqual(400, ((UserDataTestObject)result.GetObjectValue()).Foo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CanUseBinaryOperationsWithScriptTypes()
|
||||||
|
{
|
||||||
|
UserDataHandler.RegisterType("testObject", typeof(UserDataTestObject));
|
||||||
|
using (var script = new Script(@"
|
||||||
|
function test(testObject a)
|
||||||
|
return a + 500
|
||||||
|
end
|
||||||
|
"))
|
||||||
|
{
|
||||||
|
var diags = script.Diagnostics.GetDiagnostics();
|
||||||
|
foreach (var diag in diags)
|
||||||
|
{
|
||||||
|
throw new Exception(script.Diagnostics.GetFullDiagnosticMessage(diag));
|
||||||
|
}
|
||||||
|
|
||||||
|
script.Evaluate();
|
||||||
|
var a = new UserDataTestObject();
|
||||||
|
var result = script.CallFunction("test", a);
|
||||||
|
Assert.AreEqual(700, ((UserDataTestObject)result.GetObjectValue()).Foo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue