diff --git a/PorygonSharp/EvalValues/EvalValueCreator.cs b/PorygonSharp/EvalValues/EvalValueCreator.cs index 43eb1d9..c585254 100644 --- a/PorygonSharp/EvalValues/EvalValueCreator.cs +++ b/PorygonSharp/EvalValues/EvalValueCreator.cs @@ -11,7 +11,7 @@ namespace PorygonSharp.EvalValues public static EvalValue CreateValue(object o) { var type = o.GetType(); - if (type.IsEnum) + if (type.IsEnum && !type.IsGenericParameter) { var typeHash = UserDataHandler.GetTypeId(type); var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); @@ -41,6 +41,8 @@ namespace PorygonSharp.EvalValues case TypeCode.Object: if (typeof(IList).IsAssignableFrom(type)) return CreateListEvalValue((IList)o, type); + if (!UserDataHandler.IsTypeRegistered(type)) + return null; var typeHash = UserDataHandler.GetTypeId(type); var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); diff --git a/PorygonSharp/PorygonSharp.csproj b/PorygonSharp/PorygonSharp.csproj index e67c354..b529212 100644 --- a/PorygonSharp/PorygonSharp.csproj +++ b/PorygonSharp/PorygonSharp.csproj @@ -10,5 +10,4 @@ PreserveNewest - diff --git a/PorygonSharp/Script.cs b/PorygonSharp/Script.cs index fd2cdc2..dcefbcb 100644 --- a/PorygonSharp/Script.cs +++ b/PorygonSharp/Script.cs @@ -43,23 +43,43 @@ namespace PorygonSharp private Diagnostics _diagnostics; public Diagnostics Diagnostics => _diagnostics ?? (_diagnostics = new Diagnostics(_internalScript.Diagnostics)); + public bool HasErrors => Diagnostics.HasErrors(); private static readonly RuntimeTypeHandle SetupHandle = typeof(CoreSetup).TypeHandle; - public Script(string s) + public Script(string s, ScriptOptions options = null) { // Ensure core setup has been called RuntimeHelpers.RunClassConstructor(SetupHandle); - - _internalScriptHandle = Create(s); + + var optionsPointer = options?.GetRawPointer() ?? IntPtr.Zero; + _internalScriptHandle = Create(s, optionsPointer); _internalScript = Marshal.PtrToStructure(_internalScriptHandle); } + private Script(IntPtr ptr) + { + _internalScriptHandle = ptr; + _internalScript = Marshal.PtrToStructure(_internalScriptHandle); + } + + public static Script Clone(Script script) + { + // Ensure core setup has been called + RuntimeHelpers.RunClassConstructor(SetupHandle); + return new Script(CloneScript(script._internalScriptHandle)); + } + public void Dispose() { Marshal.FreeHGlobal(_internalScriptHandle); } - + + internal IntPtr GetRawPointer() + { + return _internalScriptHandle; + } + public EvalValue Evaluate() { var ptr = Evaluate(_internalScriptHandle); @@ -108,7 +128,7 @@ namespace PorygonSharp } [DllImport("libPorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr Create([MarshalAs(UnmanagedType.LPWStr)]string s); + private static extern IntPtr Create([MarshalAs(UnmanagedType.LPWStr)]string s, IntPtr options); [DllImport("libPorygonLang", EntryPoint = "EvaluateScript", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr Evaluate(IntPtr script); [DllImport("libPorygonLang", EntryPoint = "HasVariable", CallingConvention = CallingConvention.Cdecl)] @@ -122,6 +142,10 @@ namespace PorygonSharp [DllImport("libPorygonLang", EntryPoint = "CallFunction", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr CallFunction(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key, IntPtr[] parameters, int parameterCount); + + [DllImport("libPorygonLang", EntryPoint = "CloneScript", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr CloneScript(IntPtr script); + } } \ No newline at end of file diff --git a/PorygonSharp/ScriptOptions.cs b/PorygonSharp/ScriptOptions.cs new file mode 100644 index 0000000..280a0c8 --- /dev/null +++ b/PorygonSharp/ScriptOptions.cs @@ -0,0 +1,67 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +// ReSharper disable PrivateFieldCanBeConvertedToLocalVariable + +namespace PorygonSharp +{ + public abstract class ScriptOptions + { + private readonly IntPtr _ptr; + private delegate void PrintDelegate(string s); + private delegate bool ModuleExistsDelegate(IntPtr namePtr, int size); + private delegate IntPtr ResolveModuleDelegate(IntPtr namePtr, int size); + + private readonly PrintDelegate _print; + private readonly ModuleExistsDelegate _moduleExists; + private readonly ResolveModuleDelegate _resolveModule; + + protected ScriptOptions() + { + _ptr = Create(); + _print = Print; + SetOptionPrintFunc(_ptr, Marshal.GetFunctionPointerForDelegate(_print)); + _moduleExists = (namePtr, size) => + { + var nameArr = new byte[size]; + for (var i = 0; i < size; i++) + nameArr[i] = Marshal.ReadByte(namePtr, i); + var name = Encoding.UTF8.GetString(nameArr); + return ModuleExists(name); + }; + SetOptionModuleExistsFunc(_ptr, Marshal.GetFunctionPointerForDelegate(_moduleExists)); + _resolveModule = (namePtr, size) => + { + var nameArr = new byte[size]; + for (var i = 0; i < size; i++) + nameArr[i] = Marshal.ReadByte(namePtr, i); + var name = Encoding.UTF8.GetString(nameArr); + return ResolveModule(name).GetRawPointer(); + }; + SetOptionResolveModuleFunc(_ptr, Marshal.GetFunctionPointerForDelegate(_resolveModule)); + } + + protected abstract void Print(string s); + protected abstract bool ModuleExists(string s); + protected abstract Script ResolveModule(string s); + + internal IntPtr GetRawPointer() + { + return _ptr; + } + + + [DllImport("libPorygonLang", EntryPoint = "CreateOptions", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr Create(); + + [DllImport("libPorygonLang", EntryPoint = "SetOptionPrintFunc", CallingConvention = CallingConvention.Cdecl)] + private static extern void SetOptionPrintFunc(IntPtr opt, IntPtr func); + + [DllImport("libPorygonLang", EntryPoint = "SetOptionModuleExistsFunc", CallingConvention = CallingConvention.Cdecl)] + private static extern void SetOptionModuleExistsFunc(IntPtr opt, IntPtr func); + + [DllImport("libPorygonLang", EntryPoint = "SetOptionResolveModuleFunc", CallingConvention = CallingConvention.Cdecl)] + private static extern void SetOptionResolveModuleFunc(IntPtr opt, IntPtr func); + + } +} \ No newline at end of file diff --git a/PorygonSharp/ScriptType/ScriptType.cs b/PorygonSharp/ScriptType/ScriptType.cs index cb83ac5..f743e05 100644 --- a/PorygonSharp/ScriptType/ScriptType.cs +++ b/PorygonSharp/ScriptType/ScriptType.cs @@ -9,11 +9,13 @@ namespace PorygonSharp.ScriptType { internal static class ScriptType { - internal static IntPtr GetScriptType(Type t) + internal static IntPtr? GetScriptType(Type t) { - if (t.IsEnum) + if (t.IsEnum && !t.IsGenericParameter) { - return UserDataHandler.CreateUserDataType(t); + if (UserDataHandler.IsTypeRegistered(t)) + return UserDataHandler.CreateUserDataType(t); + return CreateNumericScriptType(true, false); } var typeCode = Type.GetTypeCode(t); switch (typeCode) @@ -49,30 +51,44 @@ namespace PorygonSharp.ScriptType { return CreateUserDataListType(t); } - if (typeof(IDictionary<,>).IsAssignableFrom(t)) + if (typeof(IDictionary).IsAssignableFrom(t)) { return CreateUserDataDictionaryType(t); } - goto default; + + var attr = t.GetCustomAttribute(); + if (attr != null) + { + UserDataHandler.RegisterType(attr.Identifier, t); + return UserDataHandler.CreateUserDataType(t); + } + return null; default: - throw new ArgumentOutOfRangeException(t.FullName); + return null; } } - internal static IntPtr GetFunctionScriptType(MethodInfo info) + internal static IntPtr? GetFunctionScriptType(MethodInfo info) { try { var returnType = GetScriptType(info.ReturnType); + if (!returnType.HasValue) + return null; 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); + var parameterType = GetScriptType(parameter.ParameterType); + if (!parameterType.HasValue) + { + return null; + } + parameterFuncs[index] = parameterType.Value; } - return CreateUserDataFunctionScriptType(returnType, parameterFuncs, parameters.Length); + return CreateUserDataFunctionScriptType(returnType.Value, parameterFuncs, parameters.Length); } catch { @@ -80,19 +96,23 @@ namespace PorygonSharp.ScriptType } } - private static IntPtr CreateUserDataListType(Type t) + private static IntPtr? CreateUserDataListType(Type t) { var keyType = CreateNumericScriptType(true, false); var valType = t.IsArray ? t.GetElementType() : t.GenericTypeArguments[0]; var valueType = GetScriptType(valType); - return CreateCollectionType(keyType, valueType); + if (valueType.HasValue) + return CreateCollectionType(keyType, valueType.Value); + return null; } - private static IntPtr CreateUserDataDictionaryType(Type t) + private static IntPtr? CreateUserDataDictionaryType(Type t) { var keyType = GetScriptType(t.GenericTypeArguments[0]); var valueType = GetScriptType(t.GenericTypeArguments[1]); - return CreateCollectionType(keyType, valueType); + if (keyType.HasValue && valueType.HasValue) + return CreateCollectionType(keyType.Value, valueType.Value); + return null; } [DllImport("libPorygonLang", EntryPoint = "CreateScriptType", CallingConvention = CallingConvention.Cdecl)] diff --git a/PorygonSharp/StaticScope.cs b/PorygonSharp/StaticScope.cs index 7a56698..46e3f02 100644 --- a/PorygonSharp/StaticScope.cs +++ b/PorygonSharp/StaticScope.cs @@ -13,7 +13,9 @@ namespace PorygonSharp var scriptType = ScriptType.ScriptType.GetScriptType(type); var hash = name.ScriptHash(); var value = EvalValueCreator.CreateValue(o); - RegisterStaticVariable(hash, scriptType, value.GetPointer()); + if (!scriptType.HasValue) + return; + RegisterStaticVariable(hash, scriptType.Value, value.GetPointer()); } [DllImport("libPorygonLang", EntryPoint = "RegisterStaticVariable", CallingConvention = CallingConvention.Cdecl)] diff --git a/PorygonSharp/UserData/UserDataHandler.cs b/PorygonSharp/UserData/UserDataHandler.cs index e032298..9e0e2c8 100644 --- a/PorygonSharp/UserData/UserDataHandler.cs +++ b/PorygonSharp/UserData/UserDataHandler.cs @@ -40,10 +40,13 @@ namespace PorygonSharp.UserData public static void RegisterType(string name, Type type) { var hash = name.ScriptHash(); - RegisterUserDataType(hash); - if (UserDataLookup.ContainsKey(type)) - return; - UserDataLookup.Add(type, hash); + lock (UserDataLookup) + { + if (UserDataLookup.ContainsKey(type)) + return; + RegisterUserDataType(hash); + UserDataLookup.Add(type, hash); + } const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Static; @@ -69,9 +72,9 @@ namespace PorygonSharp.UserData public static void RegisterEnumType(string name, Type type) { var hash = name.ScriptHash(); - RegisterUserDataType(hash); if (UserDataLookup.ContainsKey(type)) return; + RegisterUserDataType(hash); UserDataLookup.Add(type, hash); var values = Enum.GetValues(type); foreach (var value in values) @@ -107,7 +110,9 @@ namespace PorygonSharp.UserData setterPtr = Marshal.GetFunctionPointerForDelegate(setter); } var scriptType = ScriptType.ScriptType.GetScriptType(field.FieldType); - var userDataField = CreateUserDataField(scriptType, Marshal.GetFunctionPointerForDelegate(getter), + if (!scriptType.HasValue) + return; + var userDataField = CreateUserDataField(scriptType.Value, Marshal.GetFunctionPointerForDelegate(getter), setterPtr); var fieldName = field.Name.ScriptHash(); @@ -139,7 +144,9 @@ namespace PorygonSharp.UserData setterPtr = Marshal.GetFunctionPointerForDelegate(setter); } var scriptType = ScriptType.ScriptType.GetScriptType(property.PropertyType); - var userDataField = CreateUserDataField(scriptType, getterPtr, setterPtr); + if (!scriptType.HasValue) + return; + var userDataField = CreateUserDataField(scriptType.Value, getterPtr, setterPtr); var fieldName = property.Name.ScriptHash(); RegisterUserDataField(typeHash, fieldName, userDataField); @@ -172,9 +179,9 @@ namespace PorygonSharp.UserData }); var getterPtr = Marshal.GetFunctionPointerForDelegate(getter); var type = ScriptType.ScriptType.GetFunctionScriptType(method); - if (type == IntPtr.Zero) + if (type == IntPtr.Zero || !type.HasValue) return; - var userDataField = CreateUserDataField(type, getterPtr, IntPtr.Zero); + var userDataField = CreateUserDataField(type.Value, getterPtr, IntPtr.Zero); var fieldName = method.Name.ScriptHash(); RegisterUserDataField(typeHash, fieldName, userDataField); diff --git a/PorygonSharp/libPorygonLang.so b/PorygonSharp/libPorygonLang.so index d1bec0f..5dde80c 100755 Binary files a/PorygonSharp/libPorygonLang.so and b/PorygonSharp/libPorygonLang.so differ