Large amount of fixes and improvements

This commit is contained in:
Deukhoofd 2019-08-24 18:51:43 +02:00
parent 6ecbfe2074
commit ef2a514e54
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 151 additions and 30 deletions

View File

@ -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)));

View File

@ -10,5 +10,4 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -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<InternalScript>(_internalScriptHandle);
}
private Script(IntPtr ptr)
{
_internalScriptHandle = ptr;
_internalScript = Marshal.PtrToStructure<InternalScript>(_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)]
@ -123,5 +143,9 @@ namespace PorygonSharp
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);
}
}

View File

@ -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);
}
}

View File

@ -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<Attributes.PorygonUserdataAttribute>();
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)]

View File

@ -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)]

View File

@ -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);

Binary file not shown.