using System; using System.Globalization; namespace AspClassic.Scripting; [Serializable] public struct SourceSpan { private readonly SourceLocation _start; private readonly SourceLocation _end; public static readonly SourceSpan None = new SourceSpan(SourceLocation.None, SourceLocation.None); public static readonly SourceSpan Invalid = new SourceSpan(SourceLocation.Invalid, SourceLocation.Invalid); public SourceLocation Start => _start; public SourceLocation End => _end; public int Length => _end.Index - _start.Index; public bool IsValid { get { if (_start.IsValid) { return _end.IsValid; } return false; } } public SourceSpan(SourceLocation start, SourceLocation end) { ValidateLocations(start, end); _start = start; _end = end; } private static void ValidateLocations(SourceLocation start, SourceLocation end) { if (start.IsValid && end.IsValid) { if (start > end) { throw new ArgumentException("Start and End must be well ordered"); } } else if (start.IsValid || end.IsValid) { throw new ArgumentException("Start and End must both be valid or both invalid"); } } public static bool operator ==(SourceSpan left, SourceSpan right) { if (left._start == right._start) { return left._end == right._end; } return false; } public static bool operator !=(SourceSpan left, SourceSpan right) { if (!(left._start != right._start)) { return left._end != right._end; } return true; } public override bool Equals(object obj) { if (!(obj is SourceSpan sourceSpan)) { return false; } if (_start == sourceSpan._start) { return _end == sourceSpan._end; } return false; } public override string ToString() { SourceLocation start = _start; string text = start.ToString(); SourceLocation end = _end; return text + " - " + end.ToString(); } public override int GetHashCode() { return _start.Column ^ (_end.Column << 7) ^ (_start.Line << 14) ^ (_end.Line << 23); } internal string ToDebugString() { return string.Format(CultureInfo.CurrentCulture, "{0}-{1}", new object[2] { _start.ToDebugString(), _end.ToDebugString() }); } }