Skip to content

Instantly share code, notes, and snippets.

@bondsbw
Last active January 17, 2022 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bondsbw/6d76260ab00b4cc34b2b2f2091b782ae to your computer and use it in GitHub Desktop.
Save bondsbw/6d76260ab00b4cc34b2b2f2091b782ae to your computer and use it in GitHub Desktop.
C# without semicolons or braces
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#light
namespace Microsoft.CodeAnalysis.CSharp
using System
using System.Collections.Generic
using System.Collections.Immutable
using System.Diagnostics
using System.Text
using System.Threading
using System.Threading.Tasks
using Microsoft.CodeAnalysis.CSharp.Syntax
using Microsoft.CodeAnalysis.Text
using Roslyn.Utilities
using InternalSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
public abstract partial class CSharpSyntaxTree : SyntaxTree
internal static readonly SyntaxTree Dummy = new DummySyntaxTree()
public new abstract CSharpParseOptions Options { get }
protected T CloneNodeAsRoot<T>(T node) where T : CSharpSyntaxNode =>
CSharpSyntaxNode.CloneNodeAsRoot(node, this)
public new abstract CSharpSyntaxNode GetRoot(CancellationToken cancellationToken = default(CancellationToken))
public abstract bool TryGetRoot(out CSharpSyntaxNode root)
public new virtual Task<CSharpSyntaxNode> GetRootAsync(CancellationToken cancellationToken = default(CancellationToken))
CSharpSyntaxNode node
return Task.FromResult(this.TryGetRoot(out node) ? node : this.GetRoot(cancellationToken))
public CompilationUnitSyntax GetCompilationUnitRoot(CancellationToken cancellationToken = default(CancellationToken)) =>
(CompilationUnitSyntax)this.GetRoot(cancellationToken)
public override bool IsEquivalentTo(SyntaxTree tree, bool topLevel = false) =>
SyntaxFactory.AreEquivalent(this, tree, topLevel)
internal bool HasReferenceDirectives
get
Debug.Assert(HasCompilationUnitRoot)
return Options.Kind == SourceCodeKind.Script && GetCompilationUnitRoot().GetReferenceDirectives().Count > 0
internal bool HasReferenceOrLoadDirectives
get
Debug.Assert(HasCompilationUnitRoot)
if (Options.Kind == SourceCodeKind.Script)
var compilationUnitRoot = GetCompilationUnitRoot()
return compilationUnitRoot.GetReferenceDirectives().Count > 0 || compilationUnitRoot.GetLoadDirectives().Count > 0
return false
private bool _hasDirectives
private InternalSyntax.DirectiveStack _directives
internal void SetDirectiveStack(InternalSyntax.DirectiveStack directives)
_directives = directives
_hasDirectives = true
private InternalSyntax.DirectiveStack GetDirectives()
if (!_hasDirectives)
var stack = this.GetRoot().CsGreen.ApplyDirectives(default(InternalSyntax.DirectiveStack))
SetDirectiveStack(stack)
return _directives
internal bool IsAnyPreprocessorSymbolDefined(ImmutableArray<string> conditionalSymbols)
Debug.Assert(conditionalSymbols != null)
foreach (string conditionalSymbol in conditionalSymbols)
if (IsPreprocessorSymbolDefined(conditionalSymbol))
return true
return false
internal bool IsPreprocessorSymbolDefined(string symbolName) =>
IsPreprocessorSymbolDefined(GetDirectives(), symbolName)
private bool IsPreprocessorSymbolDefined(InternalSyntax.DirectiveStack directives, string symbolName)
switch (directives.IsDefined(symbolName))
case InternalSyntax.DefineState.Defined:
return true
case InternalSyntax.DefineState.Undefined:
return false
default:
return this.Options.PreprocessorSymbols.Contains(symbolName)
private ImmutableArray<int> _preprocessorStateChangePositions
private ImmutableArray<InternalSyntax.DirectiveStack> _preprocessorStates
internal bool IsPreprocessorSymbolDefined(string symbolName, int position)
if (_preprocessorStateChangePositions.IsDefault)
BuildPreprocessorStateChangeMap()
int searchResult = _preprocessorStateChangePositions.BinarySearch(position)
InternalSyntax.DirectiveStack directives
if (searchResult < 0)
searchResult = (~searchResult) - 1
if (searchResult >= 0)
directives = _preprocessorStates[searchResult]
else
directives = InternalSyntax.DirectiveStack.Empty
else
directives = _preprocessorStates[searchResult]
return IsPreprocessorSymbolDefined(directives, symbolName)
private void BuildPreprocessorStateChangeMap()
InternalSyntax.DirectiveStack currentState = InternalSyntax.DirectiveStack.Empty
var positions = ArrayBuilder<int>.GetInstance()
var states = ArrayBuilder<InternalSyntax.DirectiveStack>.GetInstance()
foreach (DirectiveTriviaSyntax directive in this.GetRoot().GetDirectives(d =>
switch (d.Kind())
case SyntaxKind.IfDirectiveTrivia:
case SyntaxKind.ElifDirectiveTrivia:
case SyntaxKind.ElseDirectiveTrivia:
case SyntaxKind.EndIfDirectiveTrivia:
case SyntaxKind.DefineDirectiveTrivia:
case SyntaxKind.UndefDirectiveTrivia:
return true
default:
return false
))
currentState = directive.ApplyDirectives(currentState)
switch (directive.Kind())
case SyntaxKind.IfDirectiveTrivia:
break
case SyntaxKind.ElifDirectiveTrivia:
states.Add(currentState)
positions.Add(((ElifDirectiveTriviaSyntax)directive).ElifKeyword.SpanStart)
break
case SyntaxKind.ElseDirectiveTrivia:
states.Add(currentState)
positions.Add(((ElseDirectiveTriviaSyntax)directive).ElseKeyword.SpanStart)
break
case SyntaxKind.EndIfDirectiveTrivia:
states.Add(currentState)
positions.Add(((EndIfDirectiveTriviaSyntax)directive).EndIfKeyword.SpanStart)
break
case SyntaxKind.DefineDirectiveTrivia:
states.Add(currentState)
positions.Add(((DefineDirectiveTriviaSyntax)directive).Name.SpanStart)
break
case SyntaxKind.UndefDirectiveTrivia:
states.Add(currentState)
positions.Add(((UndefDirectiveTriviaSyntax)directive).Name.SpanStart)
break
default:
throw ExceptionUtilities.UnexpectedValue(directive.Kind())
#if DEBUG
int currentPos = -1
foreach (int pos in positions)
Debug.Assert(currentPos < pos)
currentPos = pos
#endif
ImmutableInterlocked.InterlockedInitialize(ref _preprocessorStates, states.ToImmutableAndFree())
ImmutableInterlocked.InterlockedInitialize(ref _preprocessorStateChangePositions, positions.ToImmutableAndFree())
public static SyntaxTree Create(CSharpSyntaxNode root, CSharpParseOptions options = null, string path = "", Encoding encoding = null)
if (root == null)
throw new ArgumentNullException(nameof(root))
var directives = root.Kind() == SyntaxKind.CompilationUnit ?
((CompilationUnitSyntax)root).GetConditionalDirectivesStack() :
InternalSyntax.DirectiveStack.Empty
return new ParsedSyntaxTree(
textOpt: null,
encodingOpt: encoding,
checksumAlgorithm: SourceHashAlgorithm.Sha1,
path: path,
options: options ?? CSharpParseOptions.Default,
root: root,
directives: directives)
internal static SyntaxTree CreateForDebugger(CSharpSyntaxNode root, SourceText text)
Debug.Assert(root != null)
return new DebuggerSyntaxTree(root, text)
internal static SyntaxTree CreateWithoutClone(CSharpSyntaxNode root)
Debug.Assert(root != null)
return new ParsedSyntaxTree(
textOpt: null,
encodingOpt: null,
checksumAlgorithm: SourceHashAlgorithm.Sha1,
path: "",
options: CSharpParseOptions.Default,
root: root,
directives: InternalSyntax.DirectiveStack.Empty,
cloneRoot: false)
public static SyntaxTree ParseText(
string text,
CSharpParseOptions options = null,
string path = "",
Encoding encoding = null,
CancellationToken cancellationToken = default(CancellationToken))
return ParseText(SourceText.From(text, encoding), options, path, cancellationToken)
public static SyntaxTree ParseText(
SourceText text,
CSharpParseOptions options = null,
string path = "",
CancellationToken cancellationToken = default(CancellationToken))
if (text == null)
throw new ArgumentNullException(nameof(text))
options = options ?? CSharpParseOptions.Default
using (var lexer = new InternalSyntax.Lexer(text, options))
using (var parser = new InternalSyntax.LanguageParser(lexer, oldTree: null, changes: null, cancellationToken: cancellationToken))
var compilationUnit = (CompilationUnitSyntax)parser.ParseCompilationUnit().CreateRed()
var tree = new ParsedSyntaxTree(text, text.Encoding, text.ChecksumAlgorithm, path, options, compilationUnit, parser.Directives)
tree.VerifySource()
return tree
public override SyntaxTree WithChangedText(SourceText newText)
SourceText oldText
if (this.TryGetText(out oldText))
var changes = newText.GetChangeRanges(oldText)
if (changes.Count == 0 && newText == oldText)
return this
return this.WithChanges(newText, changes)
return this.WithChanges(newText, new[] { new TextChangeRange(new TextSpan(0, this.Length), newText.Length) })
private SyntaxTree WithChanges(SourceText newText, IReadOnlyList<TextChangeRange> changes)
if (changes == null)
throw new ArgumentNullException(nameof(changes))
var oldTree = this
if (changes.Count == 1 && changes[0].Span == new TextSpan(0, this.Length) && changes[0].NewLength == newText.Length)
changes = null
oldTree = null
using (var lexer = new InternalSyntax.Lexer(newText, this.Options))
using (var parser = new InternalSyntax.LanguageParser(lexer, oldTree?.GetRoot(), changes))
var compilationUnit = (CompilationUnitSyntax)parser.ParseCompilationUnit().CreateRed()
var tree = new ParsedSyntaxTree(newText, newText.Encoding, newText.ChecksumAlgorithm, this.FilePath, this.Options, compilationUnit, parser.Directives)
tree.VerifySource(changes)
return tree
public override IList<TextSpan> GetChangedSpans(SyntaxTree oldTree)
if (oldTree == null)
throw new ArgumentNullException(nameof(oldTree))
return SyntaxDiffer.GetPossiblyDifferentTextSpans(oldTree, this)
public override IList<TextChange> GetChanges(SyntaxTree oldTree)
if (oldTree == null)
throw new ArgumentNullException(nameof(oldTree))
return SyntaxDiffer.GetTextChanges(oldTree, this)
public override FileLinePositionSpan GetLineSpan(TextSpan span, CancellationToken cancellationToken = default(CancellationToken))
return new FileLinePositionSpan(this.FilePath, GetLinePosition(span.Start), GetLinePosition(span.End))
public override FileLinePositionSpan GetMappedLineSpan(TextSpan span, CancellationToken cancellationToken = default(CancellationToken))
if (_lazyLineDirectiveMap == null)
Interlocked.CompareExchange(ref _lazyLineDirectiveMap, new CSharpLineDirectiveMap(this), null)
return _lazyLineDirectiveMap.TranslateSpan(this.GetText(cancellationToken), this.FilePath, span)
public override LineVisibility GetLineVisibility(int position, CancellationToken cancellationToken = default(CancellationToken))
if (_lazyLineDirectiveMap == null)
Interlocked.CompareExchange(ref _lazyLineDirectiveMap, new CSharpLineDirectiveMap(this), null)
return _lazyLineDirectiveMap.GetLineVisibility(this.GetText(cancellationToken), position)
internal override FileLinePositionSpan GetMappedLineSpanAndVisibility(TextSpan span, out bool isHiddenPosition)
if (_lazyLineDirectiveMap == null)
Interlocked.CompareExchange(ref _lazyLineDirectiveMap, new CSharpLineDirectiveMap(this), null)
return _lazyLineDirectiveMap.TranslateSpanAndVisibility(this.GetText(), this.FilePath, span, out isHiddenPosition)
public override bool HasHiddenRegions()
if (_lazyLineDirectiveMap == null)
Interlocked.CompareExchange(ref _lazyLineDirectiveMap, new CSharpLineDirectiveMap(this), null)
return _lazyLineDirectiveMap.HasAnyHiddenRegions()
internal ReportDiagnostic GetPragmaDirectiveWarningState(string id, int position)
if (_lazyPragmaWarningStateMap == null)
Interlocked.CompareExchange(ref _lazyPragmaWarningStateMap, new CSharpPragmaWarningStateMap(this), null)
return _lazyPragmaWarningStateMap.GetWarningState(id, position)
private CSharpLineDirectiveMap _lazyLineDirectiveMap
private CSharpPragmaWarningStateMap _lazyPragmaWarningStateMap
private LinePosition GetLinePosition(int position) =>
this.GetText().Lines.GetLinePosition(position)
public override Location GetLocation(TextSpan span) =>
new SourceLocation(this, span)
public override IEnumerable<Diagnostic> GetDiagnostics(SyntaxNode node)
if (node == null)
throw new ArgumentNullException(nameof(node))
return GetDiagnostics(node.Green, node.Position)
private IEnumerable<Diagnostic> GetDiagnostics(GreenNode greenNode, int position)
if (greenNode == null)
throw new InvalidOperationException()
if (greenNode.ContainsDiagnostics)
return EnumerateDiagnostics(greenNode, position)
return SpecializedCollections.EmptyEnumerable<Diagnostic>()
private IEnumerable<Diagnostic> EnumerateDiagnostics(GreenNode node, int position)
var enumerator = new SyntaxTreeDiagnosticEnumerator(this, node, position)
while (enumerator.MoveNext())
yield return enumerator.Current
public override IEnumerable<Diagnostic> GetDiagnostics(SyntaxToken token) =>
GetDiagnostics(token.Node, token.Position)
public override IEnumerable<Diagnostic> GetDiagnostics(SyntaxTrivia trivia) =>
GetDiagnostics(trivia.UnderlyingNode, trivia.Position)
public override IEnumerable<Diagnostic> GetDiagnostics(SyntaxNodeOrToken nodeOrToken) =>
GetDiagnostics(nodeOrToken.UnderlyingNode, nodeOrToken.Position)
public override IEnumerable<Diagnostic> GetDiagnostics(CancellationToken cancellationToken = default(CancellationToken)) =>
this.GetDiagnostics(this.GetRoot(cancellationToken))
protected override SyntaxNode GetRootCore(CancellationToken cancellationToken) =>
this.GetRoot(cancellationToken)
protected override async Task<SyntaxNode> GetRootAsyncCore(CancellationToken cancellationToken) =>
await this.GetRootAsync(cancellationToken).ConfigureAwait(false)
protected override bool TryGetRootCore(out SyntaxNode root)
CSharpSyntaxNode node
if (this.TryGetRoot(out node))
root = node
return true
else
root = null
return false
protected override ParseOptions OptionsCore =>
this.Options
@Xyncgas
Copy link

Xyncgas commented Jan 17, 2022

wow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment