PorygonSharp/PorygonSharp/Script.cs

127 lines
4.7 KiB
C#

using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using PorygonSharp.DiagnosticHandling;
using PorygonSharp.EvalValues;
namespace PorygonSharp
{
[StructLayout(LayoutKind.Sequential)]
internal struct InternalScript
{
private readonly IntPtr _evaluator;
private readonly IntPtr _scriptVariables;
private readonly IntPtr _scriptTypes;
private readonly SharedPointer<object> _boundScript;
private readonly SharedPointer<object> _returnType;
private readonly IntPtr _scriptOptions;
internal readonly SharedPointer<Diagnostics> Diagnostics;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SharedPointer<T>
{
private readonly IntPtr _pointer;
private readonly int _references;
public static implicit operator IntPtr(SharedPointer<T> o)
{
return o._pointer;
}
public T Unwrap()
{
return Marshal.PtrToStructure<T>(_pointer);
}
}
public class Script : IDisposable
{
private readonly IntPtr _internalScriptHandle;
private readonly InternalScript _internalScript;
private Diagnostics _diagnostics;
public Diagnostics Diagnostics => _diagnostics ?? (_diagnostics = new Diagnostics(_internalScript.Diagnostics));
private static readonly RuntimeTypeHandle SetupHandle = typeof(CoreSetup).TypeHandle;
public Script(string s)
{
// Ensure core setup has been called
RuntimeHelpers.RunClassConstructor(SetupHandle);
_internalScriptHandle = Create(s);
_internalScript = Marshal.PtrToStructure<InternalScript>(_internalScriptHandle);
}
public void Dispose()
{
Marshal.FreeHGlobal(_internalScriptHandle);
}
public EvalValue Evaluate()
{
var ptr = Evaluate(_internalScriptHandle);
using (var result = new EvaluateResult(ptr))
{
if (result.IsSuccess())
{
return result.GetValue();
}
throw new EvaluationException(result.GetError());
}
}
public bool HasVariable(string key)
{
return HasVariable(_internalScriptHandle, key);
}
public EvalValue GetVariable(string key)
{
var ptr = GetVariable(_internalScriptHandle, key);
return new EvalValue(ptr);
}
public bool HasFunction(string key)
{
return HasFunction(_internalScriptHandle, key);
}
public EvalValue CallFunction(string key, params object[] parameters)
{
var scriptParameters = parameters.Select(x => EvalValueCreator.CreateValue(x).GetPointer()).ToArray();
var ptr = CallFunction(_internalScriptHandle, key, scriptParameters, scriptParameters.Length);
foreach (var parameter in scriptParameters)
{
Marshal.FreeHGlobal(parameter);
}
using (var result = new EvaluateResult(ptr))
{
if (result.IsSuccess())
{
return result.GetValue();
}
throw new EvaluationException(result.GetError());
}
}
[DllImport("libPorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Create([MarshalAs(UnmanagedType.LPWStr)]string s);
[DllImport("libPorygonLang", EntryPoint = "EvaluateScript", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Evaluate(IntPtr script);
[DllImport("libPorygonLang", EntryPoint = "HasVariable", CallingConvention = CallingConvention.Cdecl)]
private static extern bool HasVariable(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key);
[DllImport("libPorygonLang", EntryPoint = "GetVariable", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetVariable(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key);
[DllImport("libPorygonLang", EntryPoint = "HasFunction", CallingConvention = CallingConvention.Cdecl)]
private static extern bool HasFunction(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key);
[DllImport("libPorygonLang", EntryPoint = "CallFunction", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CallFunction(IntPtr script, [MarshalAs(UnmanagedType.LPWStr)]string key,
IntPtr[] parameters, int parameterCount);
}
}