populate GlobalCode.sourceMaps

This commit is contained in:
2025-12-11 14:06:54 -07:00
parent 92f0d22805
commit 3edf0324c7
6 changed files with 113 additions and 21 deletions

View File

@@ -113,6 +113,34 @@ public static unsafe class SlangExtensions
return toReturn;
}
public static unsafe List<SourceMapEntry> ToList(this Vec_FfiSourceMapEntry_t vec)
{
var toReturn = new List<SourceMapEntry>((int)vec.len);
var currentPtr = vec.ptr;
for (int i = 0; i < (int)vec.len; i++)
{
var item = currentPtr[i];
toReturn.Add(
new SourceMapEntry
{
Ic10Line = item.line_number,
SlangSource = new Range
{
EndCol = item.span.end_col,
EndLine = item.span.end_line,
StartCol = item.span.start_col,
StartLine = item.span.start_line,
},
}
);
}
return toReturn;
}
private static uint GetColorForKind(uint kind)
{
switch (kind)

View File

@@ -71,18 +71,6 @@ public unsafe struct Vec_uint8_t {
public UIntPtr cap;
}
public unsafe partial class Ffi {
/// <summary>
/// C# handles strings as UTF16. We do NOT want to allocate that memory in C# because
/// we want to avoid GC. So we pass it to Rust to handle all the memory allocations.
/// This should result in the ability to compile many times without triggering frame drops
/// from the GC from a <c>GetBytes()</c> call on a string in C#.
/// </summary>
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
Vec_uint8_t compile_from_string (
slice_ref_uint16_t input);
}
[StructLayout(LayoutKind.Sequential, Size = 16)]
public unsafe struct FfiRange_t {
public UInt32 start_col;
@@ -94,6 +82,44 @@ public unsafe struct FfiRange_t {
public UInt32 end_line;
}
[StructLayout(LayoutKind.Sequential, Size = 20)]
public unsafe struct FfiSourceMapEntry_t {
public UInt32 line_number;
public FfiRange_t span;
}
/// <summary>
/// Same as [<c>Vec<T></c>][<c>rust::Vec</c>], but with guaranteed <c>#[repr(C)]</c> layout
/// </summary>
[StructLayout(LayoutKind.Sequential, Size = 24)]
public unsafe struct Vec_FfiSourceMapEntry_t {
public FfiSourceMapEntry_t * ptr;
public UIntPtr len;
public UIntPtr cap;
}
[StructLayout(LayoutKind.Sequential, Size = 48)]
public unsafe struct FfiCompilationResult_t {
public Vec_uint8_t output_code;
public Vec_FfiSourceMapEntry_t source_map;
}
public unsafe partial class Ffi {
/// <summary>
/// C# handles strings as UTF16. We do NOT want to allocate that memory in C# because
/// we want to avoid GC. So we pass it to Rust to handle all the memory allocations.
/// This should result in the ability to compile many times without triggering frame drops
/// from the GC from a <c>GetBytes()</c> call on a string in C#.
/// </summary>
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
FfiCompilationResult_t compile_from_string (
slice_ref_uint16_t input);
}
[StructLayout(LayoutKind.Sequential, Size = 48)]
public unsafe struct FfiDiagnostic_t {
public Vec_uint8_t message;
@@ -146,6 +172,12 @@ public unsafe partial class Ffi {
Vec_FfiDocumentedItem_t v);
}
public unsafe partial class Ffi {
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
void free_ffi_compilation_result (
FfiCompilationResult_t input);
}
public unsafe partial class Ffi {
[DllImport(RustLib, ExactSpelling = true)] public static unsafe extern
void free_ffi_diagnostic_vec (

View File

@@ -15,11 +15,29 @@ public static class GlobalCode
// so that save file data is smaller
private static Dictionary<Guid, string> codeDict = new();
private static Dictionary<Guid, Dictionary<uint, List<Range>>> sourceMaps = new();
public static void ClearCache()
{
codeDict.Clear();
}
public static void SetSourceMap(Guid reference, List<SourceMapEntry> sourceMapEntries)
{
var builtDictionary = new Dictionary<uint, List<Range>>();
foreach (var entry in sourceMapEntries)
{
if (!builtDictionary.ContainsKey(entry.Ic10Line))
{
builtDictionary[entry.Ic10Line] = new();
}
builtDictionary[entry.Ic10Line].Add(entry.SlangSource);
}
sourceMaps[reference] = builtDictionary;
}
public static string GetSource(Guid reference)
{
if (!codeDict.ContainsKey(reference))

View File

@@ -23,6 +23,12 @@ public struct Diagnostic
public Range Range;
}
public struct SourceMapEntry
{
public Range SlangSource;
public uint Ic10Line;
}
public static class Marshal
{
private static IntPtr _libraryHandle = IntPtr.Zero;
@@ -78,11 +84,16 @@ public static class Marshal
}
}
public static unsafe bool CompileFromString(string inputString, out string compiledString)
public static unsafe bool CompileFromString(
string inputString,
out string compiledString,
out List<SourceMapEntry> sourceMapEntries
)
{
if (String.IsNullOrEmpty(inputString) || !EnsureLibLoaded())
{
compiledString = String.Empty;
sourceMapEntries = new();
return false;
}
@@ -95,19 +106,16 @@ public static class Marshal
};
var result = Ffi.compile_from_string(input);
try
{
if ((ulong)result.len < 1)
{
compiledString = String.Empty;
return false;
}
compiledString = result.AsString();
sourceMapEntries = result.source_map.ToList();
compiledString = result.output_code.AsString();
return true;
}
finally
{
result.Drop();
Ffi.free_ffi_compilation_result(result);
}
}
}

View File

@@ -26,7 +26,7 @@ public static class SlangPatches
// guard to ensure we have valid IC10 before continuing
if (
!SlangPlugin.IsSlangSource(ref result)
|| !Marshal.CompileFromString(result, out string compiled)
|| !Marshal.CompileFromString(result, out var compiled, out var sourceMap)
|| string.IsNullOrEmpty(compiled)
)
{
@@ -37,6 +37,7 @@ public static class SlangPatches
// Ensure we cache this compiled code for later retreival.
GlobalCode.SetSource(thisRef, result);
GlobalCode.SetSourceMap(thisRef, sourceMap);
_currentlyEditingGuid = null;

View File

@@ -94,6 +94,11 @@ impl From<lsp_types::Diagnostic> for FfiDiagnostic {
}
}
#[ffi_export]
pub fn free_ffi_compilation_result(input: FfiCompilationResult) {
drop(input)
}
#[ffi_export]
pub fn free_ffi_token_vec(v: safer_ffi::Vec<FfiToken>) {
drop(v)