195 lines
5.1 KiB
C#
195 lines
5.1 KiB
C#
namespace Slang;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using Assets.Scripts.UI;
|
|
using StationeersIC10Editor;
|
|
|
|
public struct Range
|
|
{
|
|
public uint StartCol;
|
|
public uint EndCol;
|
|
public uint StartLine;
|
|
public uint EndLine;
|
|
}
|
|
|
|
public struct Diagnostic
|
|
{
|
|
public string Message;
|
|
public int Severity;
|
|
public Range Range;
|
|
}
|
|
|
|
public static class Marshal
|
|
{
|
|
private static IntPtr _libraryHandle = IntPtr.Zero;
|
|
|
|
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
|
|
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
|
|
|
[DllImport("kernel32", SetLastError = true)]
|
|
private static extern bool FreeLibrary(IntPtr hModule);
|
|
|
|
private static bool EnsureLibLoaded()
|
|
{
|
|
if (_libraryHandle != IntPtr.Zero)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
try
|
|
{
|
|
_libraryHandle = LoadLibrary(ExtractNativeLibrary(Ffi.RustLib));
|
|
CodeFormatters.RegisterFormatter("Slang", typeof(SlangFormatter), true);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
L.Error($"Failed to init slang compiler: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool Init()
|
|
{
|
|
return EnsureLibLoaded();
|
|
}
|
|
|
|
public static bool Destroy()
|
|
{
|
|
if (_libraryHandle == IntPtr.Zero)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
try
|
|
{
|
|
FreeLibrary(_libraryHandle);
|
|
_libraryHandle = IntPtr.Zero;
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
L.Warning($"Unable to free handle to slang compiler's dll. {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static unsafe bool CompileFromString(string inputString, out string compiledString)
|
|
{
|
|
if (String.IsNullOrEmpty(inputString) || !EnsureLibLoaded())
|
|
{
|
|
compiledString = String.Empty;
|
|
return false;
|
|
}
|
|
|
|
fixed (char* ptrString = inputString)
|
|
{
|
|
var input = new slice_ref_uint16_t
|
|
{
|
|
ptr = (ushort*)ptrString,
|
|
len = (UIntPtr)inputString.Length,
|
|
};
|
|
|
|
var result = Ffi.compile_from_string(input);
|
|
try
|
|
{
|
|
if ((ulong)result.len < 1)
|
|
{
|
|
compiledString = String.Empty;
|
|
return false;
|
|
}
|
|
compiledString = result.AsString();
|
|
return true;
|
|
}
|
|
finally
|
|
{
|
|
result.Drop();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static unsafe List<Diagnostic> DiagnoseSource(string inputString)
|
|
{
|
|
if (string.IsNullOrEmpty(inputString) || !EnsureLibLoaded())
|
|
{
|
|
return new();
|
|
}
|
|
|
|
fixed (char* ptrInput = inputString)
|
|
{
|
|
var input = new slice_ref_uint16_t
|
|
{
|
|
ptr = (ushort*)ptrInput,
|
|
len = (UIntPtr)inputString.Length,
|
|
};
|
|
|
|
return Ffi.diagnose_source(input).ToList();
|
|
}
|
|
}
|
|
|
|
public static unsafe StyledLine TokenizeLine(string inputString)
|
|
{
|
|
if (string.IsNullOrEmpty(inputString) || !EnsureLibLoaded())
|
|
{
|
|
return new StyledLine(inputString ?? "");
|
|
}
|
|
|
|
fixed (char* ptrInputStr = inputString)
|
|
{
|
|
var strRef = new slice_ref_uint16_t
|
|
{
|
|
len = (UIntPtr)inputString.Length,
|
|
ptr = (ushort*)ptrInputStr,
|
|
};
|
|
|
|
var tokens = Ffi.tokenize_line(strRef);
|
|
L.Debug($"Tokenized line '{inputString}' into {tokens.len} tokens.");
|
|
return tokens.ToLine(inputString);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the currently documented items from the Slang compiler and returns new StationpediaPages with correct formatting.
|
|
/// </summary>
|
|
public static unsafe List<StationpediaPage> GetSlangDocs()
|
|
{
|
|
return Ffi.get_docs().ToList();
|
|
}
|
|
|
|
private static string ExtractNativeLibrary(string libName)
|
|
{
|
|
string destinationPath = Path.Combine(Path.GetTempPath(), libName);
|
|
|
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
|
|
|
using (Stream stream = assembly.GetManifestResourceStream(libName))
|
|
{
|
|
if (stream == null)
|
|
{
|
|
L.Error(
|
|
$"{libName} not found. This means it was not embedded in the mod. Please contact the mod author!"
|
|
);
|
|
return "";
|
|
}
|
|
|
|
try
|
|
{
|
|
using (FileStream fileStream = new FileStream(destinationPath, FileMode.Create))
|
|
{
|
|
stream.CopyTo(fileStream);
|
|
}
|
|
return destinationPath;
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
L.Warning($"Could not overwrite {libName} (it might be in use): {e.Message}");
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
}
|