// 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;
}
}
}
}