Support for setting binary operations
This commit is contained in:
parent
8c3db0373b
commit
ae2080f145
|
@ -57,7 +57,7 @@ namespace PorygonSharp.EvalValues
|
|||
return str;
|
||||
}
|
||||
|
||||
public object EvaluateGenericObject()
|
||||
private object EvaluateGenericObject()
|
||||
{
|
||||
var ptr = EvaluateUserDataObj(_handle);
|
||||
return GCHandle.FromIntPtr(ptr).Target;
|
||||
|
|
|
@ -131,9 +131,11 @@ namespace PorygonSharp
|
|||
public string GetBoundTreeString()
|
||||
{
|
||||
var length = GetTreeStringLength(_internalScriptHandle);
|
||||
var sb = new StringBuilder(length - 4);
|
||||
var sb = new StringBuilder(length);
|
||||
GetTreeString(_internalScriptHandle, sb);
|
||||
return sb.ToString();
|
||||
var s = sb.ToString();
|
||||
s = s.Substring(0, length);
|
||||
return s;
|
||||
}
|
||||
|
||||
[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.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using PorygonSharp.EvalValues;
|
||||
using PorygonSharp.Utilities;
|
||||
|
||||
namespace PorygonSharp.UserData
|
||||
|
@ -43,6 +44,7 @@ namespace PorygonSharp.UserData
|
|||
|
||||
SetIsCastableFunc(id, Marshal.GetFunctionPointerForDelegate(_isCastableFunc));
|
||||
SetCastFunc(id, Marshal.GetFunctionPointerForDelegate(_castFunc));
|
||||
|
||||
}
|
||||
|
||||
internal void RegisterFields()
|
||||
|
@ -79,6 +81,8 @@ namespace PorygonSharp.UserData
|
|||
{
|
||||
RegisterFunction(method);
|
||||
}
|
||||
|
||||
RegisterOperations();
|
||||
}
|
||||
|
||||
private void RegisterField(FieldInfo field)
|
||||
|
@ -150,9 +154,9 @@ namespace PorygonSharp.UserData
|
|||
var obj = GCHandle.FromIntPtr(objPtr).Target;
|
||||
var objType = obj.GetType();
|
||||
if (expectedType.IsAssignableFrom(objType))
|
||||
return objPtr;
|
||||
return EvalValueCreator.CreateValue(obj).GetPointer();
|
||||
if (objType.IsAssignableFrom(expectedType))
|
||||
return objPtr;
|
||||
return EvalValueCreator.CreateValue(obj).GetPointer();
|
||||
if (_implicitCasts.TryGetValue(expectedType, out var func))
|
||||
{
|
||||
var castVal = func.Invoke(null, new[] {obj});
|
||||
|
@ -168,6 +172,54 @@ namespace PorygonSharp.UserData
|
|||
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)]
|
||||
internal static extern void RegisterUserDataField(uint hashId, uint fieldId, IntPtr field);
|
||||
|
||||
|
@ -179,6 +231,10 @@ namespace PorygonSharp.UserData
|
|||
|
||||
[DllImport("PorygonLang", EntryPoint = "SetCastFunc", CallingConvention = CallingConvention.Cdecl)]
|
||||
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 val = eval.GetObjectValue();
|
||||
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);
|
||||
evaluatedParameters[i] = convertedType;
|
||||
|
|
Binary file not shown.
|
@ -27,6 +27,18 @@ namespace PorygonSharpTests
|
|||
{
|
||||
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]
|
||||
|
@ -311,5 +323,53 @@ end
|
|||
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