2025-09-27 02:22:15 -05:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
2025-11-27 23:41:04 -06:00
|
|
|
using System.Linq;
|
2025-11-28 20:27:34 -06:00
|
|
|
using System.Text;
|
2025-09-27 02:22:15 -05:00
|
|
|
|
|
|
|
|
namespace Microsoft.Iris.Debug.Symbols;
|
|
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
[CLSCompliant(false)]
|
2025-09-27 02:22:15 -05:00
|
|
|
public class ApplicationDebugSymbols
|
|
|
|
|
{
|
|
|
|
|
public List<FileDebugSymbols> Files { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
[CLSCompliant(false)]
|
2025-09-27 02:22:15 -05:00
|
|
|
public class FileDebugSymbols
|
|
|
|
|
{
|
2025-11-27 23:41:04 -06:00
|
|
|
private string[] _sourceCodeLines;
|
|
|
|
|
|
|
|
|
|
public string OriginalFileName { get; set; }
|
2025-09-27 02:22:15 -05:00
|
|
|
|
|
|
|
|
public string CompiledFileName { get; set; }
|
|
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
public string SourceFileName { get; set; }
|
2025-09-27 02:22:15 -05:00
|
|
|
|
2025-11-28 18:05:23 -06:00
|
|
|
public SourceMap SourceMap { get; } = new();
|
2025-11-27 23:41:04 -06:00
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
public (uint Offset, SourceSpan Span) GetLocationFromPosition(SourcePosition pos)
|
2025-11-27 23:41:04 -06:00
|
|
|
{
|
2025-11-28 18:05:23 -06:00
|
|
|
var foundLocation = SourceMap.Xml.FirstOrDefault(kvp =>
|
2025-11-27 23:41:04 -06:00
|
|
|
{
|
|
|
|
|
var offset = kvp.Key;
|
|
|
|
|
var span = kvp.Value;
|
|
|
|
|
return span.Contains(pos);
|
2025-11-28 18:05:23 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (foundLocation.Equals(default(KeyValuePair<uint, SourceSpan>)))
|
|
|
|
|
throw new KeyNotFoundException($"No offset was assigned to line {pos.Line}, column {pos.Column}");
|
|
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
return (foundLocation.Key, foundLocation.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint OffsetByLineAndColumn(int line, int col) => OffsetByLineAndColumn(new(line, col));
|
|
|
|
|
|
|
|
|
|
public SourceSpan GetContainingSpan(SourcePosition pos) => GetLocationFromPosition(pos).Span;
|
|
|
|
|
|
|
|
|
|
public uint OffsetByLineAndColumn(SourcePosition pos) => GetLocationFromPosition(pos).Offset;
|
|
|
|
|
|
|
|
|
|
public string GetSourceSubstring(SourceSpan span)
|
|
|
|
|
{
|
|
|
|
|
if (!HasSourceCode())
|
|
|
|
|
throw new InvalidOperationException($"Must supply source with {nameof(SetSourceCode)}");
|
|
|
|
|
|
|
|
|
|
span.Start.AsZeroIndexed(out var startLine, out var startColumn);
|
|
|
|
|
span.End.AsZeroIndexed(out var endLine, out var endColumn);
|
|
|
|
|
|
|
|
|
|
StringBuilder sb = new();
|
|
|
|
|
|
|
|
|
|
int currentLineIndex = startLine;
|
|
|
|
|
while (currentLineIndex <= endLine)
|
|
|
|
|
{
|
|
|
|
|
var line = _sourceCodeLines[currentLineIndex];
|
|
|
|
|
|
|
|
|
|
Index lineStartIndex = currentLineIndex == startLine
|
|
|
|
|
? startColumn
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
Index lineEndIndex = currentLineIndex == endLine
|
|
|
|
|
? endColumn
|
|
|
|
|
: ^1;
|
|
|
|
|
|
|
|
|
|
sb.AppendLine(line[lineStartIndex..lineEndIndex]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.ToString();
|
2025-11-27 23:41:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetSourceCode(string source)
|
|
|
|
|
{
|
|
|
|
|
_sourceCodeLines = source.Split('\n')
|
|
|
|
|
.Select(s => s.TrimEnd('\r'))
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
2025-11-28 20:27:34 -06:00
|
|
|
|
|
|
|
|
public bool HasSourceCode() => _sourceCodeLines is not null;
|
2025-11-27 23:41:04 -06:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
[CLSCompliant(false)]
|
2025-11-28 18:05:23 -06:00
|
|
|
public class SourceMap
|
|
|
|
|
{
|
|
|
|
|
public Dictionary<uint, SourceSpan> Xml { get; } = [];
|
|
|
|
|
public Dictionary<uint, Tuple<int, int>> Script { get; } = [];
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
[DebuggerDisplay("L{Line}C{Column}")]
|
|
|
|
|
public class SourcePosition : IComparable<SourcePosition>, IEquatable<SourcePosition>
|
|
|
|
|
{
|
|
|
|
|
public int Line { get; }
|
|
|
|
|
|
|
|
|
|
public int Column { get; }
|
|
|
|
|
|
|
|
|
|
private ulong Position => ((ulong)Line << (sizeof(uint) * 8)) | (uint)Column;
|
|
|
|
|
|
|
|
|
|
public SourcePosition(int line, int column)
|
|
|
|
|
{
|
|
|
|
|
if (line <= 0)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(line));
|
|
|
|
|
|
|
|
|
|
if (column <= 0)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(line));
|
|
|
|
|
|
|
|
|
|
Line = line;
|
|
|
|
|
Column = column;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 20:27:34 -06:00
|
|
|
public void AsZeroIndexed(out int line, out int column)
|
|
|
|
|
{
|
|
|
|
|
line = Line - 1;
|
|
|
|
|
column = Column - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
public int CompareTo(SourcePosition other) => Position.CompareTo(other.Position);
|
|
|
|
|
|
|
|
|
|
public bool Equals(SourcePosition other) => Position == other.Position;
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj is not SourcePosition other)
|
|
|
|
|
return false;
|
|
|
|
|
return Equals(other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
int hashCode = 533871040;
|
|
|
|
|
hashCode = hashCode * -1521134295 + Line.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + Column.GetHashCode();
|
|
|
|
|
hashCode = hashCode * -1521134295 + Position.GetHashCode();
|
|
|
|
|
return hashCode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool operator <(SourcePosition left, SourcePosition right) => left.CompareTo(right) < 0;
|
|
|
|
|
|
|
|
|
|
public static bool operator >(SourcePosition left, SourcePosition right) => left.CompareTo(right) > 0;
|
|
|
|
|
|
|
|
|
|
public static bool operator <=(SourcePosition left, SourcePosition right) => left.CompareTo(right) <= 0;
|
|
|
|
|
|
|
|
|
|
public static bool operator >=(SourcePosition left, SourcePosition right) => left.CompareTo(right) >= 0;
|
|
|
|
|
|
|
|
|
|
public static bool operator ==(SourcePosition left, SourcePosition right) => left.Equals(right);
|
|
|
|
|
|
|
|
|
|
public static bool operator !=(SourcePosition left, SourcePosition right) => !(left == right);
|
2025-09-27 02:22:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[DebuggerDisplay("[{Start}..{End}]")]
|
|
|
|
|
public class SourceSpan
|
|
|
|
|
{
|
2025-11-27 23:41:04 -06:00
|
|
|
public SourceSpan(SourcePosition start, SourcePosition end)
|
2025-09-27 02:22:15 -05:00
|
|
|
{
|
|
|
|
|
if (start > end)
|
|
|
|
|
throw new ArgumentException($"Source start index must be at or after end index.");
|
|
|
|
|
|
|
|
|
|
Start = start;
|
|
|
|
|
End = end;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
public SourcePosition Start { get; }
|
2025-09-27 02:22:15 -05:00
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
public SourcePosition End { get; }
|
2025-09-27 02:22:15 -05:00
|
|
|
|
2025-11-27 23:41:04 -06:00
|
|
|
public bool Contains(SourcePosition pos) => Start >= pos && pos < End;
|
2025-09-27 02:22:15 -05:00
|
|
|
}
|
|
|
|
|
|