Files
2026-08-27 10:56:38 -06:00

282 lines
6.7 KiB
C#

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax;
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal readonly struct DirectiveStack
{
public static readonly DirectiveStack Empty = new DirectiveStack(ConsList<Directive>.Empty);
private readonly ConsList<Directive>? _directives;
public bool IsNull => _directives == null;
public bool IsEmpty => _directives == ConsList<Directive>.Empty;
private DirectiveStack(ConsList<Directive>? directives)
{
_directives = directives;
}
public static void InterlockedInitialize(ref DirectiveStack location, DirectiveStack value)
{
Interlocked.CompareExchange(ref Unsafe.AsRef(in location._directives), value._directives, null);
}
public DefineState IsDefined(string id)
{
for (ConsList<Directive> val = _directives; val != null && val.Any(); val = val.Tail)
{
switch (val.Head.Kind)
{
case SyntaxKind.DefineDirectiveTrivia:
if (!(val.Head.GetIdentifier() == id))
{
continue;
}
return DefineState.Defined;
case SyntaxKind.UndefDirectiveTrivia:
if (!(val.Head.GetIdentifier() == id))
{
continue;
}
return DefineState.Undefined;
case SyntaxKind.ElifDirectiveTrivia:
case SyntaxKind.ElseDirectiveTrivia:
break;
default:
continue;
}
do
{
val = val.Tail;
if (val == null || !val.Any())
{
return DefineState.Unspecified;
}
}
while (val.Head.Kind != SyntaxKind.IfDirectiveTrivia);
}
return DefineState.Unspecified;
}
public bool PreviousBranchTaken()
{
ConsList<Directive> val = _directives;
while (val != null && val.Any())
{
if (val.Head.BranchTaken)
{
return true;
}
if (val.Head.Kind == SyntaxKind.IfDirectiveTrivia)
{
return false;
}
val = val.Tail;
}
return false;
}
public bool HasUnfinishedIf()
{
ConsList<Directive> previousIfElifElseOrRegion = GetPreviousIfElifElseOrRegion(_directives);
if (previousIfElifElseOrRegion != null && previousIfElifElseOrRegion.Any())
{
return previousIfElifElseOrRegion.Head.Kind != SyntaxKind.RegionDirectiveTrivia;
}
return false;
}
public bool HasPreviousIfOrElif()
{
ConsList<Directive> previousIfElifElseOrRegion = GetPreviousIfElifElseOrRegion(_directives);
if (previousIfElifElseOrRegion != null && previousIfElifElseOrRegion.Any())
{
if (previousIfElifElseOrRegion.Head.Kind != SyntaxKind.IfDirectiveTrivia)
{
return previousIfElifElseOrRegion.Head.Kind == SyntaxKind.ElifDirectiveTrivia;
}
return true;
}
return false;
}
public bool HasUnfinishedRegion()
{
ConsList<Directive> previousIfElifElseOrRegion = GetPreviousIfElifElseOrRegion(_directives);
if (previousIfElifElseOrRegion != null && previousIfElifElseOrRegion.Any())
{
return previousIfElifElseOrRegion.Head.Kind == SyntaxKind.RegionDirectiveTrivia;
}
return false;
}
public DirectiveStack Add(Directive directive)
{
switch (directive.Kind)
{
case SyntaxKind.EndIfDirectiveTrivia:
{
ConsList<Directive> previousIf = GetPreviousIf(_directives);
bool include;
if (previousIf != null && previousIf.Any())
{
return new DirectiveStack(CompleteIf(_directives, out include));
}
break;
}
case SyntaxKind.EndRegionDirectiveTrivia:
{
ConsList<Directive> previousRegion = GetPreviousRegion(_directives);
if (previousRegion != null && previousRegion.Any())
{
return new DirectiveStack(CompleteRegion(_directives));
}
break;
}
}
return new DirectiveStack(new ConsList<Directive>(directive, _directives ?? ConsList<Directive>.Empty));
}
private static ConsList<Directive> CompleteIf(ConsList<Directive> stack, out bool include)
{
if (!stack.Any())
{
include = true;
return stack;
}
if (stack.Head.Kind == SyntaxKind.IfDirectiveTrivia)
{
include = stack.Head.BranchTaken;
return stack.Tail;
}
ConsList<Directive> val = CompleteIf(stack.Tail, out include);
SyntaxKind kind = stack.Head.Kind;
if (kind - 8549 <= SyntaxKind.List)
{
include = stack.Head.BranchTaken;
}
else if (include)
{
val = new ConsList<Directive>(stack.Head, val);
}
return val;
}
private static ConsList<Directive> CompleteRegion(ConsList<Directive> stack)
{
if (!stack.Any())
{
return stack;
}
if (stack.Head.Kind == SyntaxKind.RegionDirectiveTrivia)
{
return stack.Tail;
}
ConsList<Directive> val = CompleteRegion(stack.Tail);
return new ConsList<Directive>(stack.Head, val);
}
private static ConsList<Directive>? GetPreviousIf(ConsList<Directive>? directives)
{
ConsList<Directive> val = directives;
while (val != null && val.Any())
{
if (val.Head.Kind == SyntaxKind.IfDirectiveTrivia)
{
return val;
}
val = val.Tail;
}
return val;
}
private static ConsList<Directive>? GetPreviousIfElifElseOrRegion(ConsList<Directive>? directives)
{
ConsList<Directive> val = directives;
while (val != null && val.Any())
{
SyntaxKind kind = val.Head.Kind;
if (kind - 8548 <= (SyntaxKind)2 || kind == SyntaxKind.RegionDirectiveTrivia)
{
return val;
}
val = val.Tail;
}
return val;
}
private static ConsList<Directive>? GetPreviousRegion(ConsList<Directive>? directives)
{
ConsList<Directive> val = directives;
while (val != null && val.Any() && val.Head.Kind != SyntaxKind.RegionDirectiveTrivia)
{
val = val.Tail;
}
return val;
}
internal string GetDebuggerDisplay()
{
if (IsNull)
{
return "<null>";
}
if (IsEmpty)
{
return "[]";
}
StringBuilder stringBuilder = new StringBuilder();
ConsList<Directive> val = _directives;
while (val != null && val.Any())
{
if (stringBuilder.Length > 0)
{
stringBuilder.Insert(0, " | ");
}
stringBuilder.Insert(0, val.Head.GetDebuggerDisplay());
val = val.Tail;
}
return stringBuilder.ToString();
}
public bool IncrementallyEquivalent(DirectiveStack other)
{
ConsList<Directive> val = SkipInsignificantDirectives(_directives);
ConsList<Directive> val2 = SkipInsignificantDirectives(other._directives);
bool flag = val?.Any() ?? false;
bool flag2 = val2?.Any() ?? false;
while (flag && flag2)
{
if (!val.Head.IncrementallyEquivalent(val2.Head))
{
return false;
}
val = SkipInsignificantDirectives(val.Tail);
val2 = SkipInsignificantDirectives(val2.Tail);
flag = val?.Any() ?? false;
flag2 = val2?.Any() ?? false;
}
return flag == flag2;
}
private static ConsList<Directive>? SkipInsignificantDirectives(ConsList<Directive>? directives)
{
while (directives != null && directives.Any())
{
SyntaxKind kind = directives.Head.Kind;
if (kind - 8548 <= (SyntaxKind)7)
{
return directives;
}
directives = directives.Tail;
}
return directives;
}
}