// 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.Text; namespace QtVsTools.SyntaxAnalysis { using static RegExprAssert; //////////////////////////////////////////////////////////////////////////////////////////////// /// /// RegExprAssert ( -> RegExpr) /// //////////////////////////////////////////////////////////////////////////////////////////////// /// /// Asserts a pattern on the input string without consuming chars. /// /// public partial class RegExprAssert : RegExpr { public enum AssertLook { Ahead, Behind } public AssertLook Context { get; set; } public bool Negative { get; set; } public RegExpr Expr { get; set; } protected override IEnumerable OnRender(RegExpr defaultTokenWs, RegExpr parent, StringBuilder pattern, ref RenderMode mode, Stack tokenStack) { base.OnRender(defaultTokenWs, parent, pattern, ref mode, tokenStack); if (mode.HasFlag(RenderMode.Assert)) throw new NestedAssertException(); switch (Context) { case AssertLook.Ahead: pattern.Append(Negative ? "(?!" : "(?="); break; case AssertLook.Behind: pattern.Append(Negative ? "(? tokenStack) { base.OnRenderEnd(defaultTokenWs, parent, pattern, ref mode, tokenStack); pattern.Append(")"); mode &= ~RenderMode.Assert; } } public abstract partial class RegExpr { RegExprAssert AsAssert() { if (this is RegExprAssert) return this as RegExprAssert; return new RegExprAssert { Context = AssertLook.Ahead, Negative = false, Expr = this }; } public static RegExprAssert AssertLookAhead(RegExpr expr) { var assert = expr.AsAssert(); return new RegExprAssert { Context = AssertLook.Ahead, Negative = assert.Negative, Expr = assert.Expr }; } public static RegExprAssert AssertLookBehind(RegExpr expr) { var assert = expr.AsAssert(); return new RegExprAssert { Context = AssertLook.Behind, Negative = assert.Negative, Expr = assert.Expr }; } public static RegExprAssert AssertNegated(RegExpr expr) { var assert = expr.AsAssert(); return new RegExprAssert { Context = assert.Context, Negative = !assert.Negative, Expr = assert.Expr }; } public delegate RegExprAssert AssertTemplate(RegExpr expr); public class AssertExprBuilder { AssertTemplate Template { get; } public AssertExprBuilder(AssertTemplate template) { Template = template; } public class Expr { public RegExprAssert Assert { get; set; } public Expr(RegExprAssert assert) { Assert = assert; } public static implicit operator RegExpr(Expr e) { return e.Assert; } public static RegExpr operator &(RegExpr rx1, Expr rx2) { return Concat(rx1, rx2); } public static RegExpr operator |(RegExpr rx1, Expr rx2) { return Choice(rx1, rx2); } } public class NegateableExpr : Expr { public NegateableExpr(RegExprAssert assert) : base(assert) { } public static Expr operator !(NegateableExpr x) { return new Expr(AssertNegated(x.Assert)); } } public NegateableExpr this[RegExpr expr] => new(Template(expr)); } public class NestedAssertException : RegExprException { public NestedAssertException(string message = null) : base(message) { } } } }