// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 using System.Collections.Generic; using System.Linq; namespace QtVsTools.SyntaxAnalysis { public abstract partial class RegExpr { //////////////////////////////////////////////////////////////////////////////////////////// /// /// RegExpr.ParseTree /// //////////////////////////////////////////////////////////////////////////////////////////// /// /// Result of processing input text with a pattern rendered from a RegExpr. /// /// /// Nodes in a ParseTree correspond to captured tokens. The parent-child relationship /// between nodes reflects token embedding. /// public class ParseTree { public Node Root { get; set; } public const string KeyRoot = "0"; public class Node : IOperatorCapture, IOperandCapture { public string CaptureId { get; set; } public string Value { get; set; } public int Begin { get; set; } public int End { get; set; } public int GroupIdx { get; set; } public int CaptureIdx { get; set; } class NodeComparer : IComparer { public int Compare(Node x, Node y) { return Comparer.Default.Compare(x.Begin, y.Begin); } } static readonly NodeComparer _Comparer = new(); public static IComparer Comparer => _Comparer; public Token Token { get; set; } public string TokenId => Token.Id; public object Production { get; set; } public Node Parent { get; set; } public SortedList ChildNodes { get; } = new(); public ProductionObjects ChildProductions { get; } = new(); public Queue TokenStream { get; set; } public Stack OperatorStack { get; set; } public Stack OperandStack { get; set; } IProductionRule _Rule; public IProductionRule Rule { get { return _Rule ??= Token.SelectRule(this); } } public string Key { get => CaptureId == KeyRoot ? KeyRoot : $"{CaptureId}:{Begin}:{End}"; } public override string ToString() { return $"{TokenId}[{Value}]"; } public static implicit operator ParseTree(Node node) { return new ParseTree { Root = node }; } int SiblingIdx { get => Parent?.ChildNodes.IndexOfKey(Begin) ?? 0; } int SiblingCount { get => Parent?.ChildNodes.Count ?? 1; } public bool IsFirst => SiblingIdx == 0; public bool IsLast => SiblingIdx == SiblingCount - 1; public IEnumerable LookAhead(params TokenGroup[] ids) { if (Parent == null) return Empty(); var lookAhead = Parent.ChildNodes.Values .Skip(SiblingIdx + 1); if (ids.Any()) lookAhead = lookAhead.Where(x => ids.Any(g => g.Contains(x.TokenId))); return lookAhead.Cast().Concat(Items(EndOfList)); } public IEnumerable LookBehind(params TokenGroup[] ids) { if (Parent == null) return Empty(); var lookBehind = Parent.ChildNodes.Values .Take(SiblingIdx) .Reverse(); if (ids.Any()) lookBehind = lookBehind.Where(x => ids.Any(g => g.Contains(x.TokenId))); return lookBehind.Cast().Concat(Items(EndOfList)); } public bool Is(params TokenGroup[] tokenIds) { return tokenIds.Any(g => g.Contains(TokenId)); } public bool IsNot(params TokenGroup[] tokenIds) { return !tokenIds.Any(g => g.Contains(TokenId)); } public IOperandCapture Operand { get { if (Parent is not { OperandStack: { } }) return EndOfList; if (!Parent.OperandStack.Any()) return EndOfList; return Parent.OperandStack.Peek(); } } public IOperandCapture LeftOperand { get { if (Parent is not { OperandStack: { } }) return EndOfList; if (Parent.OperandStack.Count() < 2) return EndOfList; return Parent.OperandStack.Skip(1).First(); } } public IOperandCapture RightOperand { get { if (Parent is not { OperandStack: { } }) return EndOfList; if (Parent.OperandStack.Count() < 2) return EndOfList; return Parent.OperandStack.Peek(); } } public bool HasOperand => Operand != EndOfList; public bool HasLeftOperand => LeftOperand != EndOfList; public bool HasRightOperand => RightOperand != EndOfList; } } } }