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) public static EvalValue CreateValue(object o)
{ {
var type = o.GetType(); var type = o.GetType();
if (type.IsEnum) if (type.IsEnum && !type.IsGenericParameter)
{ {
var typeHash = UserDataHandler.GetTypeId(type); var typeHash = UserDataHandler.GetTypeId(type);
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
@ -41,6 +41,8 @@ namespace PorygonSharp.EvalValues
case TypeCode.Object: case TypeCode.Object:
if (typeof(IList).IsAssignableFrom(type)) if (typeof(IList).IsAssignableFrom(type))
return CreateListEvalValue((IList)o, type); return CreateListEvalValue((IList)o, type);
if (!UserDataHandler.IsTypeRegistered(type))
return null;
var typeHash = UserDataHandler.GetTypeId(type); var typeHash = UserDataHandler.GetTypeId(type);
var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); var handle = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle))); return new EvalValue(CreateUserDataEvalValue(typeHash, GCHandle.ToIntPtr(handle)));

View File

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

View File

@ -43,23 +43,43 @@ namespace PorygonSharp
private Diagnostics _diagnostics; private Diagnostics _diagnostics;
public Diagnostics Diagnostics => _diagnostics ?? (_diagnostics = new Diagnostics(_internalScript.Diagnostics)); public Diagnostics Diagnostics => _diagnostics ?? (_diagnostics = new Diagnostics(_internalScript.Diagnostics));
public bool HasErrors => Diagnostics.HasErrors();
private static readonly RuntimeTypeHandle SetupHandle = typeof(CoreSetup).TypeHandle; 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 // Ensure core setup has been called
RuntimeHelpers.RunClassConstructor(SetupHandle); RuntimeHelpers.RunClassConstructor(SetupHandle);
_internalScriptHandle = Create(s); var optionsPointer = options?.GetRawPointer() ?? IntPtr.Zero;
_internalScriptHandle = Create(s, optionsPointer);
_internalScript = Marshal.PtrToStructure<InternalScript>(_internalScriptHandle); _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() public void Dispose()
{ {
Marshal.FreeHGlobal(_internalScriptHandle); Marshal.FreeHGlobal(_internalScriptHandle);
} }
internal IntPtr GetRawPointer()
{
return _internalScriptHandle;
}
public EvalValue Evaluate() public EvalValue Evaluate()
{ {
var ptr = Evaluate(_internalScriptHandle); var ptr = Evaluate(_internalScriptHandle);
@ -108,7 +128,7 @@ namespace PorygonSharp
} }
[DllImport("libPorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)] [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)] [DllImport("libPorygonLang", EntryPoint = "EvaluateScript", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Evaluate(IntPtr script); private static extern IntPtr Evaluate(IntPtr script);
[DllImport("libPorygonLang", EntryPoint = "HasVariable", CallingConvention = CallingConvention.Cdecl)] [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, private static extern IntPtr CallFunction(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key,
IntPtr[] parameters, int parameterCount); 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 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); var typeCode = Type.GetTypeCode(t);
switch (typeCode) switch (typeCode)
@ -49,30 +51,44 @@ namespace PorygonSharp.ScriptType
{ {
return CreateUserDataListType(t); return CreateUserDataListType(t);
} }
if (typeof(IDictionary<,>).IsAssignableFrom(t)) if (typeof(IDictionary).IsAssignableFrom(t))
{ {
return CreateUserDataDictionaryType(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: default:
throw new ArgumentOutOfRangeException(t.FullName); return null;
} }
} }
internal static IntPtr GetFunctionScriptType(MethodInfo info) internal static IntPtr? GetFunctionScriptType(MethodInfo info)
{ {
try try
{ {
var returnType = GetScriptType(info.ReturnType); var returnType = GetScriptType(info.ReturnType);
if (!returnType.HasValue)
return null;
var parameters = info.GetParameters(); var parameters = info.GetParameters();
var parameterFuncs = new IntPtr[parameters.Length]; var parameterFuncs = new IntPtr[parameters.Length];
for (var index = 0; index < parameters.Length; index++) for (var index = 0; index < parameters.Length; index++)
{ {
var parameter = parameters[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 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 keyType = CreateNumericScriptType(true, false);
var valType = t.IsArray ? t.GetElementType() : t.GenericTypeArguments[0]; var valType = t.IsArray ? t.GetElementType() : t.GenericTypeArguments[0];
var valueType = GetScriptType(valType); 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 keyType = GetScriptType(t.GenericTypeArguments[0]);
var valueType = GetScriptType(t.GenericTypeArguments[1]); 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)] [DllImport("libPorygonLang", EntryPoint = "CreateScriptType", CallingConvention = CallingConvention.Cdecl)]

View File

@ -13,7 +13,9 @@ namespace PorygonSharp
var scriptType = ScriptType.ScriptType.GetScriptType(type); var scriptType = ScriptType.ScriptType.GetScriptType(type);
var hash = name.ScriptHash(); var hash = name.ScriptHash();
var value = EvalValueCreator.CreateValue(o); 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)] [DllImport("libPorygonLang", EntryPoint = "RegisterStaticVariable", CallingConvention = CallingConvention.Cdecl)]

View File

@ -40,10 +40,13 @@ namespace PorygonSharp.UserData
public static void RegisterType(string name, Type type) public static void RegisterType(string name, Type type)
{ {
var hash = name.ScriptHash(); var hash = name.ScriptHash();
RegisterUserDataType(hash); lock (UserDataLookup)
if (UserDataLookup.ContainsKey(type)) {
return; if (UserDataLookup.ContainsKey(type))
UserDataLookup.Add(type, hash); return;
RegisterUserDataType(hash);
UserDataLookup.Add(type, hash);
}
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance |
BindingFlags.FlattenHierarchy | BindingFlags.Static; BindingFlags.FlattenHierarchy | BindingFlags.Static;
@ -69,9 +72,9 @@ namespace PorygonSharp.UserData
public static void RegisterEnumType(string name, Type type) public static void RegisterEnumType(string name, Type type)
{ {
var hash = name.ScriptHash(); var hash = name.ScriptHash();
RegisterUserDataType(hash);
if (UserDataLookup.ContainsKey(type)) if (UserDataLookup.ContainsKey(type))
return; return;
RegisterUserDataType(hash);
UserDataLookup.Add(type, hash); UserDataLookup.Add(type, hash);
var values = Enum.GetValues(type); var values = Enum.GetValues(type);
foreach (var value in values) foreach (var value in values)
@ -107,7 +110,9 @@ namespace PorygonSharp.UserData
setterPtr = Marshal.GetFunctionPointerForDelegate(setter); setterPtr = Marshal.GetFunctionPointerForDelegate(setter);
} }
var scriptType = ScriptType.ScriptType.GetScriptType(field.FieldType); 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); setterPtr);
var fieldName = field.Name.ScriptHash(); var fieldName = field.Name.ScriptHash();
@ -139,7 +144,9 @@ namespace PorygonSharp.UserData
setterPtr = Marshal.GetFunctionPointerForDelegate(setter); setterPtr = Marshal.GetFunctionPointerForDelegate(setter);
} }
var scriptType = ScriptType.ScriptType.GetScriptType(property.PropertyType); 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(); var fieldName = property.Name.ScriptHash();
RegisterUserDataField(typeHash, fieldName, userDataField); RegisterUserDataField(typeHash, fieldName, userDataField);
@ -172,9 +179,9 @@ namespace PorygonSharp.UserData
}); });
var getterPtr = Marshal.GetFunctionPointerForDelegate(getter); var getterPtr = Marshal.GetFunctionPointerForDelegate(getter);
var type = ScriptType.ScriptType.GetFunctionScriptType(method); var type = ScriptType.ScriptType.GetFunctionScriptType(method);
if (type == IntPtr.Zero) if (type == IntPtr.Zero || !type.HasValue)
return; return;
var userDataField = CreateUserDataField(type, getterPtr, IntPtr.Zero); var userDataField = CreateUserDataField(type.Value, getterPtr, IntPtr.Zero);
var fieldName = method.Name.ScriptHash(); var fieldName = method.Name.ScriptHash();
RegisterUserDataField(typeHash, fieldName, userDataField); RegisterUserDataField(typeHash, fieldName, userDataField);

Binary file not shown.