using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; namespace Parser { public abstract class SyntaxNode { private readonly SyntaxNode _parent; internal readonly Internal.GreenNode _green; internal SyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) { _parent = parent; _green = green; Position = position; } private protected SyntaxNode(Internal.GreenNode green, int position) { _parent = this; _green = green; Position = position; } public TokenKind Kind => _green.Kind; public SyntaxNode Parent => _parent; public int Slots => _green.Slots; public ChildNodesAndTokensList GetChildNodesAndTokens() { return new ChildNodesAndTokensList(this); } public int Position { get; } internal int GetChildPosition(int slot) { var result = Position; while (slot > 0) { slot--; var greenChild = _green.GetSlot(slot); if (greenChild != null) { result += greenChild.FullWidth; } } return result; } internal abstract SyntaxNode? GetNode(int index); internal SyntaxNode? GetRed(ref SyntaxNode? field, int slot) { if (field == null) { var green = _green.GetSlot(slot); if (green != null) { field = green.CreateRed(this, this.GetChildPosition(slot)); } } return field; } public override string ToString() { return Text; } public virtual string Text => _green.Text; public virtual string FullText => _green.FullText; public int FullWidth => _green.FullWidth; public virtual IReadOnlyList LeadingTrivia { get { var p = Parent; return _green.LeadingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); } } public virtual IReadOnlyList TrailingTrivia { get { var p = Parent; return _green.TrailingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList(); } } public abstract void Accept(SyntaxVisitor visitor); public SyntaxDiagnostic[] GetDiagnostics() { return GetDiagnosticsRecursive(_green, Position).ToArray(); } private static IEnumerable GetDiagnosticsRecursive(Internal.GreenNode node, int position) { if (node.HasDiagnostics) { foreach (var diagnostic in node.GetDiagnostics()) { yield return SyntaxDiagnostic.From(diagnostic, position); } } for (var i = 0; i < node.Slots; i++) { var maybeChild = node.GetSlot(i); if (maybeChild is Internal.GreenNode child) { foreach (var diagnostic in GetDiagnosticsRecursive(child, position)) { yield return diagnostic; } position += child.FullWidth; } } } } public abstract class StatementSyntaxNode : SyntaxNode { internal StatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) : base(parent, green, position) { } } public abstract class ExpressionSyntaxNode : SyntaxNode { internal ExpressionSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) : base(parent, green, position) { } } public abstract class FunctionHandleSyntaxNode : ExpressionSyntaxNode { internal FunctionHandleSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) : base(parent, green, position) { } } public abstract class MethodDeclarationSyntaxNode : StatementSyntaxNode { internal MethodDeclarationSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position) : base(parent, green, position) { } } public class RootSyntaxNode : SyntaxNode { private SyntaxNode? _file; internal RootSyntaxNode(Internal.GreenNode green, int position) : base(green, position) { } internal override SyntaxNode? GetNode(int index) { throw new System.NotImplementedException(); } public override void Accept(SyntaxVisitor visitor) { throw new System.NotImplementedException(); } public FileSyntaxNode File { get { var red = this.GetRed(ref this._file, 0); if (red != null) return (FileSyntaxNode)red; throw new System.Exception("file cannot be null"); } } } }