diff --git a/PorygonSharp/EvalValues/DictionaryEvalValue.cs b/PorygonSharp/EvalValues/DictionaryEvalValue.cs new file mode 100644 index 0000000..2c255ba --- /dev/null +++ b/PorygonSharp/EvalValues/DictionaryEvalValue.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using System.Runtime.InteropServices; + +namespace PorygonSharp.EvalValues +{ + public class DictionaryEvalValue + { + private readonly IDictionary _dictionary; + private readonly Type _keyType; + private readonly Type _valueType; + + private delegate IntPtr GetterDelegate(IntPtr parent, IntPtr index); + private delegate void SetterDelegate(IntPtr parent, IntPtr index, IntPtr value); + private delegate IntPtr GetIteratorDelegate(IntPtr parent); + private delegate int GetLengthDelegate(IntPtr parent); + + // ReSharper disable PrivateFieldCanBeConvertedToLocalVariable + private readonly GetterDelegate _getter; + private readonly SetterDelegate _setter; + private readonly GetIteratorDelegate _getIterator; + private readonly GetLengthDelegate _getLength; + // ReSharper restore PrivateFieldCanBeConvertedToLocalVariable + + public readonly IntPtr GetterPtr; + public readonly IntPtr SetterPtr; + public readonly IntPtr GetIteratorPtr; + public readonly IntPtr GetLengthPtr; + + public DictionaryEvalValue(IDictionary dictionary, Type t) + { + _dictionary = dictionary; + var genericTypes = t.GetGenericArguments(); + _keyType = genericTypes[0]; + _valueType = genericTypes[1]; + + _getter = Getter; + _setter = Setter; + _getIterator = GetIterator; + _getLength = GetLength; + + GetterPtr = Marshal.GetFunctionPointerForDelegate(_getter); + SetterPtr = Marshal.GetFunctionPointerForDelegate(_setter); + GetIteratorPtr = Marshal.GetFunctionPointerForDelegate(_getIterator); + GetLengthPtr = Marshal.GetFunctionPointerForDelegate(_getLength); + } + + private IntPtr Getter(IntPtr parent, IntPtr index) + { + var val = new EvalValue(index).GetObjectValue(); + return EvalValueCreator.CreateValue(_dictionary[val]).GetPointer(); + } + + private void Setter(IntPtr parent, IntPtr index, IntPtr value) + { + var key = new EvalValue(index).GetObjectValue(); + var val = new EvalValue(value).GetObjectValue(); + _dictionary[key] = Convert.ChangeType(val, _valueType); + } + + private IntPtr GetIterator(IntPtr parent) + { + throw new NotImplementedException(); + } + + private int GetLength(IntPtr parent) + { + return _dictionary.Count; + } + + } +} \ No newline at end of file diff --git a/PorygonSharp/EvalValues/EvalValueCreator.cs b/PorygonSharp/EvalValues/EvalValueCreator.cs index f3eb749..cc5c698 100644 --- a/PorygonSharp/EvalValues/EvalValueCreator.cs +++ b/PorygonSharp/EvalValues/EvalValueCreator.cs @@ -14,9 +14,6 @@ namespace PorygonSharp.EvalValues var type = o.GetType(); if (type.IsEnum && !type.IsGenericParameter) { - var typeHash = UserDataHandler.GetTypeId(type); - var ptr = ObjectEvalValueHandler.GetObjectPtr(o); - return new EvalValue(CreateUserDataEvalValue(typeHash, ptr)); } var typeCode = Type.GetTypeCode(type); switch (typeCode) @@ -42,6 +39,8 @@ namespace PorygonSharp.EvalValues case TypeCode.Object: if (typeof(IList).IsAssignableFrom(type)) return CreateListEvalValue((IList)o, type); + if (typeof(IDictionary).IsAssignableFrom(type)) + return CreateDictionaryEvalValue((IDictionary) o, type); if (typeof(Delegate).IsAssignableFrom(type)) { return CreateDelegateEvalValue((Delegate) o); @@ -71,6 +70,14 @@ namespace PorygonSharp.EvalValues return new EvalValue(ptr); } + private static EvalValue CreateDictionaryEvalValue(IDictionary dictionary, Type t) + { + var helper = new DictionaryEvalValue(dictionary, t); + var ptr = CreateCollectionValue(IntPtr.Zero, IntPtr.Zero, helper.GetterPtr, helper.SetterPtr, + helper.GetIteratorPtr, helper.GetLengthPtr); + return new EvalValue(ptr); + } + private static EvalValue CreateDelegateEvalValue(Delegate del) { var val = new DelegateEvalValue(del); @@ -88,7 +95,7 @@ namespace PorygonSharp.EvalValues [DllImport("PorygonLang", EntryPoint = "CreateStringEvalValue",CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr CreateStringEvalValue([MarshalAs(UnmanagedType.LPWStr)]string s); [DllImport("PorygonLang", EntryPoint = "CreateUserDataEvalValue",CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr CreateUserDataEvalValue(uint typeHash, IntPtr obj); + internal static extern IntPtr CreateUserDataEvalValue(uint typeHash, IntPtr obj); [DllImport("PorygonLang", EntryPoint = "CreateFunctionEvalValue",CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr CreateFunctionEvalValue(IntPtr func, IntPtr parent); diff --git a/PorygonSharp/StaticScope.cs b/PorygonSharp/StaticScope.cs index 4e2326c..d7b12d2 100644 --- a/PorygonSharp/StaticScope.cs +++ b/PorygonSharp/StaticScope.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using PorygonSharp.EvalValues; +using PorygonSharp.UserData; using PorygonSharp.Utilities; namespace PorygonSharp @@ -20,6 +21,25 @@ namespace PorygonSharp _variables.Add(o); RegisterStaticVariable(hash, scriptType.Value, value.GetPointer()); } + + public static void RegisterStaticEnum(string name, Type type) + { + UserDataHandler.RegisterEnumType(name, type); + var typeHash = UserDataHandler.GetTypeId(type); + var scriptType = ScriptType.ScriptTypeHandler.GetScriptType(type); + if (!scriptType.HasValue) + return; + var ptr = ObjectEvalValueHandler.GetObjectPtr(Activator.CreateInstance(type)); + var val = new EvalValue(EvalValueCreator.CreateUserDataEvalValue(typeHash, ptr)); + StaticScope.RegisterStaticVariable(name, scriptType.Value, val); + } + + public static void RegisterStaticVariable(string name, IntPtr type, EvalValue val) + { + var hash = name.ScriptHash(); + RegisterStaticVariable(hash, type, val.GetPointer()); + } + [DllImport("PorygonLang", EntryPoint = "RegisterStaticVariable", CallingConvention = CallingConvention.Cdecl)] private static extern void RegisterStaticVariable(uint hashId, IntPtr scriptType, IntPtr value); diff --git a/PorygonSharp/UserData/UserDataHandler.cs b/PorygonSharp/UserData/UserDataHandler.cs index f9cf65c..f19ab83 100644 --- a/PorygonSharp/UserData/UserDataHandler.cs +++ b/PorygonSharp/UserData/UserDataHandler.cs @@ -27,8 +27,7 @@ namespace PorygonSharp.UserData var enumAttr = type.GetCustomAttribute(); if (enumAttr != null) { - RegisterEnumType(enumAttr.Name, type); - StaticScope.RegisterStaticVariable(enumAttr.Name, Activator.CreateInstance(type)); + StaticScope.RegisterStaticEnum(enumAttr.Name, type); } } } diff --git a/PorygonSharpTests/EnumUserdataTest.cs b/PorygonSharpTests/EnumUserdataTest.cs index 9b8fc35..ba6f78a 100644 --- a/PorygonSharpTests/EnumUserdataTest.cs +++ b/PorygonSharpTests/EnumUserdataTest.cs @@ -15,8 +15,7 @@ namespace PorygonSharpTests [Test] public void AbleToAccessStaticEnumVariable() { - UserDataHandler.RegisterEnumType("testEnum", typeof(testEnum)); - StaticScope.RegisterStaticVariable("testEnum", testEnum.One); + StaticScope.RegisterStaticEnum("testEnum", typeof(testEnum)); using (var script = new Script(@" return type(testEnum) ")) @@ -34,8 +33,7 @@ namespace PorygonSharpTests [Test] public void AbleToUseStaticEnumVariable() { - UserDataHandler.RegisterEnumType("testEnum", typeof(testEnum)); - StaticScope.RegisterStaticVariable("testEnum", testEnum.One); + StaticScope.RegisterStaticEnum("testEnum", typeof(testEnum)); using (var script = new Script(@" return testEnum.Three + 2 "))