// 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; using System.Reflection; namespace QtVsTools.SyntaxAnalysis { public abstract partial class RegExpr { public interface IRuleAction { int NumOperands { get; } string SourceTokenId { get; set; } bool Execute(ref T productionObj, string capturedValue, params object[] operandObjs); MethodInfo AssertInfo { get; } MethodInfo ActionInfo { get; } } public class RuleAction : IRuleAction { public Delegate Assert { get; set; } public Delegate Action { get; set; } public MethodInfo AssertInfo => Assert?.Method; public MethodInfo ActionInfo => Action?.Method; public string SourceTokenId { get; set; } static readonly int _NumOperands = (typeof(T1) != typeof(Void) ? 1 : 0) + (typeof(T2) != typeof(Void) ? 1 : 0); public int NumOperands => _NumOperands; bool TestAssert(T prod, string value, T1 x, T2 y) { return Assert switch { null => true, CaptureCallback.Predicate predicate => predicate(value), UnaryCallback.Predicate assert => assert(x), UnaryCallback.Predicate predicate1 => predicate1(prod, x), BinaryCallback.Predicate assert1 => assert1(x, y), BinaryCallback.Predicate predicate2 => predicate2(prod, x, y), _ => throw new InvalidOperationException("Incompatible assert callback.") }; } void RunAction(ref T prod, string value, T1 x, T2 y) { switch (Action) { case null: throw new InvalidOperationException("Missing action callback."); case CaptureCallback.Create create: prod = create(value); break; case UnaryCallback.Create action: prod = action(x); break; case BinaryCallback.Create create1: prod = create1(x, y); break; case UnaryCallback.Transform transform: prod = transform(prod, x); break; case BinaryCallback.Transform transform1: prod = transform1(prod, x, y); break; case UnaryCallback.Update update: update(prod, x); break; case BinaryCallback.Update update1: update1(prod, x, y); break; case UnaryCallback.Error error: throw new ErrorException(error(prod, x)); case BinaryCallback.Error error1: throw new ErrorException(error1(prod, x, y)); default: throw new InvalidOperationException("Incompatible action callback."); } } bool GetOperand(out TOperand x, object[] operands, ref int idx) { x = default; if (typeof(TOperand) == typeof(Void)) return true; if (operands.Length <= idx) return false; object operandObj = operands[idx++]; if (operandObj is TOperand operand) { x = operand; return true; } return false; } public bool Execute(ref T prod, string value, params object[] operands) { int idx = 0; if (!GetOperand(out T1 x, operands, ref idx)) return false; if (!GetOperand(out T2 y, operands, ref idx)) return false; if (!TestAssert(prod, value, x, y)) return false; RunAction(ref prod, value, x, y); return true; } } public class RuleAction : RuleAction { } public class RuleAction : RuleAction { } /////////////////////////////////////////////////////////////////////////////////////////// #region Capture public static RuleAction Capture( CaptureCallback.Predicate p, CaptureCallback.Create a) { return new RuleAction { Assert = p, Action = a }; } public static RuleAction Capture( CaptureCallback.Create a) { return new RuleAction { Assert = null, Action = a }; } #endregion Capture /////////////////////////////////////////////////////////////////////////////////////////// #region Create public static RuleAction Create( string sid, UnaryCallback.Predicate p, UnaryCallback.Create a) { return new RuleAction { SourceTokenId = sid, Assert = p, Action = a }; } public static RuleAction Create( Enum sid, UnaryCallback.Predicate p, UnaryCallback.Create a) { return Create(sid.ToString(), p, a); } public static RuleAction Create( string sid, UnaryCallback.Create a) { return Create(sid, null, a); } public static RuleAction Create( Enum sid, UnaryCallback.Create a) { return Create(sid, null, a); } public static RuleAction Create( UnaryCallback.Predicate p, UnaryCallback.Create a) { return Create(string.Empty, p, a); } public static RuleAction Create( UnaryCallback.Create a) { return Create(string.Empty, null, a); } public static RuleAction Create( BinaryCallback.Predicate p, BinaryCallback.Create a) { return new RuleAction { Assert = p, Action = a }; } public static RuleAction Create( BinaryCallback.Create a) { return Create(null, a); } #endregion Create /////////////////////////////////////////////////////////////////////////////////////////// #region Transform public static RuleAction Transform( string sid, UnaryCallback.Predicate p, UnaryCallback.Transform a) { return new RuleAction { SourceTokenId = sid, Assert = p, Action = a }; } public static RuleAction Transform( Enum sid, UnaryCallback.Predicate p, UnaryCallback.Transform a) { return Transform(sid.ToString(), p, a); } public static RuleAction Transform( string sid, UnaryCallback.Transform a) { return Transform(sid, null, a); } public static RuleAction Transform( Enum sid, UnaryCallback.Transform a) { return Transform(sid, null, a); } public static RuleAction Transform( UnaryCallback.Transform a) { return Transform(string.Empty, null, a); } public static RuleAction Transform( BinaryCallback.Predicate p, BinaryCallback.Transform a) { return new RuleAction { Assert = p, Action = a }; } public static RuleAction Transform( BinaryCallback.Transform a) { return Transform(null, a); } #endregion Transform /////////////////////////////////////////////////////////////////////////////////////////// #region Update public static RuleAction Update( string sid, UnaryCallback.Predicate p, UnaryCallback.Update a) { return new RuleAction { SourceTokenId = sid, Assert = p, Action = a }; } public static RuleAction Update( Enum sid, UnaryCallback.Predicate p, UnaryCallback.Update a) { return Update(sid.ToString(), p, a); } public static RuleAction Update( string sid, UnaryCallback.Update a) { return Update(sid, null, a); } public static RuleAction Update( Enum sid, UnaryCallback.Update a) { return Update(sid, null, a); } public static RuleAction Update( UnaryCallback.Update a) { return Update(string.Empty, null, a); } public static RuleAction Update( BinaryCallback.Predicate p, BinaryCallback.Update a) { return new RuleAction { Assert = p, Action = a }; } public static RuleAction Update( BinaryCallback.Update a) { return Update(null, a); } #endregion Update /////////////////////////////////////////////////////////////////////////////////////////// #region Error public static RuleAction Error( string sid, UnaryCallback.Predicate p, UnaryCallback.Error a) { return new RuleAction { SourceTokenId = sid, Assert = p, Action = a }; } public static RuleAction Error( Enum sid, UnaryCallback.Predicate p, UnaryCallback.Error a) { return Error(sid.ToString(), p, a); } public static RuleAction Error( string sid, UnaryCallback.Error a) { return Error(sid, null, a); } public static RuleAction Error( Enum sid, UnaryCallback.Error a) { return Error(sid, null, a); } public static RuleAction Error( UnaryCallback.Predicate p, UnaryCallback.Error a) { return Error(string.Empty, p, a); } public static RuleAction Error( UnaryCallback.Error a) { return Error(string.Empty, null, a); } public static RuleAction Error( BinaryCallback.Predicate p, BinaryCallback.Error a) { return new RuleAction { Assert = p, Action = a }; } public static RuleAction Error( BinaryCallback.Error a) { return Error(null, a); } public class ErrorException : RegExprException { public ErrorException(string message = null) : base(message) { } } #endregion Error /////////////////////////////////////////////////////////////////////////////////////////// #region Callbacks public static class CaptureCallback { public delegate bool Predicate(string capture); public delegate T Create(string capture); } public static class UnaryCallback { public delegate bool Predicate(T1 operand1); public delegate bool Predicate(T obj, T1 operand1); public delegate T Create(T1 operand1); public delegate T Transform(T obj, T1 operand1); public delegate void Update(T obj, T1 operand1); public delegate string Error(T obj, T1 operand1); } public static class BinaryCallback { public delegate bool Predicate(T1 operand1, T2 operand2); public delegate bool Predicate(T obj, T1 operand1, T2 operand2); public delegate T Create(T1 operand1, T2 operand2); public delegate T Transform(T obj, T1 operand1, T2 operand2); public delegate void Update(T obj, T1 operand1, T2 operand2); public delegate string Error(T obj, T1 operand1, T2 operand2); } #endregion Callbacks } }