prefix replaces CONDITION

This commit is contained in:
Youmu Liu
2026-07-06 18:19:32 +08:00
parent cd7a52bd60
commit b053567eb7
8 changed files with 1113 additions and 1105 deletions
@@ -0,0 +1,449 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexAnalyzerFrontEnd.PrefixEmit"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public static partial class RegexAnalyzerFrontEnd
{
internal static List<RegexIR> EmitPrefix(
List<RegexIR> irList
)
{
List<RegexIR> origin = irList;
List<RegexIR> result = new(origin.Count);
Span<RegexIR> origin_span = CollectionsMarshal.AsSpan(origin);
int region_name = 1;
EmitPrefix(origin_span, result, 0, 0);
FixLineObservation(result);
return result;
void EmitPrefix(
ReadOnlySpan<RegexIR> region,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
ReadOnlySpan<RegexIR> emit_window;
int index = 0;
while (index < region.Length)
{
emit_window = region[index..];
int emitResult;
if ((emitResult = TryEmitGroupFindPack(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else if ((emitResult = TryEmitTryGroupTail(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else if ((emitResult = TryEmitAltChain(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else if ((emitResult = TryEmitAltSuccessTail(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else if ((emitResult = TryEmitAltFailTail(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else if ((emitResult = TryEmitTryIR(emit_window, result, currentRegion, lineBase)) > 0)
{
index += emitResult;
} else
{
result.Add(CloneIR(emit_window[0], currentRegion));
index++;
}
}
}
int TryEmitTryGroupTail(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
if (origin.Length < 5 || origin[0] is not RegexTryIR _try) {
return -1;
}
int tailOffset = _try.CommandCount + 1;
if (origin.Length < tailOffset + 3 ||
origin[tailOffset] is not RegexConditionIR { SuccessCase: 2, FailCase: 1 } condition ||
origin[tailOffset + 1] is not RegexPopIR { IsSuccess: false } pop ||
origin[tailOffset + 2] is not RegexPackIR { Condition: true } pack) {
return -1;
}
int tryOutputIndex = result.Count;
int emitCount = TryEmitTryIR(
origin,
result,
currentRegion,
lineBase,
foldSingleInstructionTry: false);
if (emitCount <= 0 || result[tryOutputIndex] is not RegexTryIR emittedTry) {
return -1;
}
_ = condition;
int regionId = emittedTry.Prefix.WorkingRegion;
RegexIR prefixedPop = CloneIR(pop, regionId);
ApplyPrefix(
prefixedPop,
regionId,
RegexIRPrefixMask.Prev_Fail | RegexIRPrefixMask.Observe_Region,
regionId);
RegexIR prefixedPack = CloneIR(pack, regionId);
ApplyPrefix(
prefixedPack,
regionId,
RegexIRPrefixMask.Prev_Success | RegexIRPrefixMask.Observe_Region,
regionId);
result.Add(prefixedPop);
result.Add(prefixedPack);
return emitCount + 3;
}
int TryEmitAltChain(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
if (origin.Length < 3 ||
origin[0] is not RegexConditionIR { SuccessCase: 1, FailCase: 2 } ||
origin[1] is not RegexPopIR { IsSuccess: true } ||
origin[2] is not RegexTryIR) {
return -1;
}
int observeRegion = currentRegion;
RegexIRPrefixMask observeMask = RegexIRPrefixMask.Observe_Region;
int observeSource = currentRegion;
if (result.Count > 0)
{
RegexIR previous = result[^1];
observeRegion = GetObservedRegion(previous, currentRegion);
GetObservation(previous, result, lineBase, currentRegion, out observeMask, out observeSource);
ApplyPrefix(previous, observeRegion, RegexIRPrefixMask.Pop_Success, observeRegion);
}
RegexIRPrefixMask mask = RegexIRPrefixMask.Prev_Fail | observeMask;
int emit_count = TryEmitTryIR(origin[2..], result, currentRegion, lineBase, mask, observeSource, observeRegion);
return emit_count < 0 ? -1 : emit_count + 2;
}
int TryEmitAltSuccessTail(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
if (origin.Length < 2 ||
origin[0] is not RegexConditionIR { SuccessCase: 1, FailCase: 2 } ||
origin[1] is not RegexPopIR { IsSuccess: true } ||
result.Count == 0) {
return -1;
}
RegexIR previous = result[^1];
int observeRegion = GetObservedRegion(previous, currentRegion);
ApplyPrefix(previous, observeRegion, RegexIRPrefixMask.Pop_Success, observeRegion);
return 2;
}
int TryEmitAltFailTail(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
if (origin.Length < 1 ||
origin[0] is not RegexPopIR { IsSuccess: false } pop ||
result.Count == 0) {
return -1;
}
RegexIR previous = result[^1];
if ((previous.Prefix.Mask & RegexIRPrefixMask.Pop_Success) == 0) {
return -1;
}
GetObservation(
previous,
result,
lineBase,
currentRegion,
out RegexIRPrefixMask observeMask,
out int observeSource);
RegexIR prefixedPop = CloneIR(pop, currentRegion);
ApplyPrefix(
prefixedPop,
currentRegion,
RegexIRPrefixMask.Prev_Fail | observeMask,
observeSource);
result.Add(prefixedPop);
return 1;
}
// convert TRY into region
int TryEmitTryIR(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase,
RegexIRPrefixMask mask = 0,
int observeSource = 0,
int reuseRegion = 0,
bool foldSingleInstructionTry = true
)
{
if (origin.Length == 0 || origin[0] is not RegexTryIR _try) {
return -1;
}
int commandCount = _try.CommandCount;
if (origin.Length < commandCount + 1) {
return -1;
}
int regionId = reuseRegion == 0 ? region_name : reuseRegion;
if (reuseRegion == 0) {
region_name++;
}
if (foldSingleInstructionTry &&
commandCount == 1 &&
IsFoldableSingleTryInstruction(origin[1])) {
RegexIR folded = CloneIR(origin[1], regionId);
int foldedObserveSource =
(mask & RegexIRPrefixMask.ObserveMethod) != 0 ?
observeSource :
_try.Prefix.ObserveSource;
folded.Prefix = new RegexIRPrefix(
regionId,
folded.Prefix.Mask | _try.Prefix.Mask | mask,
foldedObserveSource);
result.Add(folded);
return commandCount + 1;
}
List<RegexIR> sub_ir = new(commandCount);
ReadOnlySpan<RegexIR> try_region = origin.Slice(1, commandCount);
EmitPrefix(try_region, sub_ir, regionId, lineBase + result.Count + 1);
RegexTryIR newTry = new(sub_ir.Count)
{
IsFullyOptimized = _try.IsFullyOptimized,
Prefix = new RegexIRPrefix(regionId, _try.Prefix.Mask | mask, observeSource)
};
result.Add(newTry);
result.AddRange(sub_ir);
return commandCount + 1;
}
int TryEmitGroupFindPack(
ReadOnlySpan<RegexIR> origin,
List<RegexIR> result,
int currentRegion,
int lineBase
)
{
if (origin.Length < 5 ||
origin[0] is not RegexTryIR { CommandCount: 1 } _try ||
origin[1] is not RegexFindComplexIR find ||
origin[2] is not RegexConditionIR { SuccessCase: 2, FailCase: 1 } ||
origin[3] is not RegexPopIR { IsSuccess: false } ||
origin[4] is not RegexPackIR { Condition: true } pack) {
return -1;
}
int regionId = region_name;
region_name++;
RegexIRPrefixMask findMask = find.Prefix.Mask | _try.Prefix.Mask;
int findObserveSource =
(find.Prefix.Mask & RegexIRPrefixMask.ObserveMethod) != 0 ?
find.Prefix.ObserveSource :
_try.Prefix.ObserveSource;
RegexFindComplexIR newFind = new(find.IsNearest, find.CommandCount)
{
IsFullyOptimized = find.IsFullyOptimized,
Prefix = new RegexIRPrefix(regionId, findMask, findObserveSource)
};
RegexPackIR newPack = new(pack.Condition, pack.GroupName)
{
Prefix = new RegexIRPrefix(
regionId,
pack.Prefix.Mask | RegexIRPrefixMask.Prev_Success | RegexIRPrefixMask.Observe_Line,
-1)
};
result.Add(newFind);
result.Add(newPack);
return 5;
}
static int GetObservedRegion(
RegexIR ir,
int currentRegion
)
{
return ir.Prefix.WorkingRegion == 0 ? currentRegion : ir.Prefix.WorkingRegion;
}
static void GetObservation(
RegexIR ir,
List<RegexIR> result,
int lineBase,
int currentRegion,
out RegexIRPrefixMask observeMask,
out int observeSource
)
{
if (IsLineObservable(ir))
{
observeMask = RegexIRPrefixMask.Observe_Line;
observeSource = -1;
} else
{
observeMask = RegexIRPrefixMask.Observe_Region;
observeSource = GetObservedRegion(ir, currentRegion);
}
}
static void FixLineObservation(
List<RegexIR> result
)
{
for (int i = 0; i < result.Count; i++)
{
RegexIRPrefix prefix = result[i].Prefix;
if ((prefix.Mask & RegexIRPrefixMask.Observe_Line) == 0) {
continue;
}
result[i].Prefix = new RegexIRPrefix(
prefix.WorkingRegion,
prefix.Mask,
i - 1);
}
}
static bool IsFoldableSingleTryInstruction(
RegexIR ir
)
{
return IsLineObservable(ir) &&
(ir.Prefix.Mask & RegexIRPrefixMask.ExeCondition) == 0 &&
(ir.Prefix.Mask & RegexIRPrefixMask.ObserveMethod) == 0;
}
static bool IsLineObservable(
RegexIR ir
)
{
return ir is RegexMatchSeqIR or
RegexMatchSetIR or
RegexCountSeqIR or
RegexCountSetIR or
RegexFindSeqIR or
RegexFindComplexIR;
}
static void ApplyPrefix(
RegexIR ir,
int workingRegion,
RegexIRPrefixMask mask,
int observeSource
)
{
ir.Prefix = new RegexIRPrefix(
workingRegion,
ir.Prefix.Mask | mask,
observeSource);
}
static RegexIR CloneIR(
RegexIR ir,
int currentRegion
)
{
RegexIR clone = ir switch
{
RegexFindComplexIR find => new RegexFindComplexIR(find.IsNearest, find.CommandCount)
{
IsFullyOptimized = find.IsFullyOptimized
},
RegexFindSeqIR find => new RegexFindSeqIR(find.Pattern, find.IsFirst),
RegexMatchSeqIR match => new RegexMatchSeqIR(match.Pattern),
RegexMatchSetIR match => new RegexMatchSetIR(match.Charset),
RegexConditionIR condition => new RegexConditionIR(condition.SuccessCase, condition.FailCase),
RegexPackIR pack => new RegexPackIR(pack.Condition, pack.GroupName),
RegexCountComplexIR count => new RegexCountComplexIR(count.Min, count.Max, count.IsGreedy, count.CommandCount)
{
IsFullyOptimized = count.IsFullyOptimized
},
RegexCountSeqIR count => new RegexCountSeqIR(count.Min, count.Max, count.IsGreedy, count.Sequence),
RegexCountSetIR count => new RegexCountSetIR(count.Min, count.Max, count.IsGreedy, count.CharSet),
RegexTryIR tryIR => new RegexTryIR(tryIR.CommandCount)
{
IsFullyOptimized = tryIR.IsFullyOptimized
},
RegexPopIR pop => new RegexPopIR(pop.IsSuccess),
_ => throw new NotSupportedException($"Unsupported IR type: {ir.GetType().Name}")
};
clone.Prefix = new RegexIRPrefix(
ir.Prefix.WorkingRegion == 0 ? currentRegion : ir.Prefix.WorkingRegion,
ir.Prefix.Mask,
ir.Prefix.ObserveSource);
return clone;
}
}
}
}
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexAnalyzer"
// file="RegexAnalyzerFrontEnd"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
@@ -29,6 +29,7 @@ using StgSharp.RegularAnalysis.Abstraction;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
@@ -76,18 +77,35 @@ namespace StgSharp.RegularAnalysis.Text
{
// RegexAnalyzer interpreter = new();
// interpreter._source = regex;
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree;
try
{
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree = GenerateAST(regex);
tree = GenerateAST(regex);
OptimizeTree(tree);
List<RegexIR> base_ir = GenerateIR(tree);
ScanAndOptimizeIR(base_ir, out List<RegexIR> opt_ir);
return new TextRegexSource(regex, tree, base_ir, opt_ir);
}
catch (Exception ex)
{
return new TextRegexSource(regex, null, null, null, ex);
}
List<RegexIR> base_ir;
try
{
base_ir = GenerateIR(tree);
}
catch (Exception ex)
{
return new TextRegexSource(regex, tree, null, null, ex);
}
try
{
ScanAndOptimizeIR(base_ir, out List<RegexIR> opt_ir);
List<RegexIR> prefix_ir = EmitPrefix(opt_ir);
return new TextRegexSource(regex, tree, base_ir, prefix_ir);
}
catch (Exception ex)
{
return new TextRegexSource(regex, tree, base_ir, null, ex);
}
}
}
@@ -0,0 +1,79 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexIR.Prefix"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
internal enum RegexIRPrefixMask
{
Prev_Success = 1 << 0,
Prev_Fail = 1 << 1,
Always = 1 << 2,
ExeCondition = Prev_Fail | Prev_Success | Always,
Pop_Fail = 1 << 3,
Pop_Success = 1 << 4,
PopCondition = Pop_Success | Pop_Fail,
Observe_Line = 1 << 5,
Observe_Region = 1 << 6,
ObserveMethod = Observe_Line | Observe_Region
}
internal record struct RegexIRPrefix(
int WorkingRegion,
RegexIRPrefixMask Mask,
int ObserveSource
)
{
public override string ToString()
{
return $"{WorkingRegion:D4}, {DisplayMask(Mask , RegexIRPrefixMask.ExeCondition):D1}, {DisplayMask(Mask , RegexIRPrefixMask.PopCondition):D1}, {DisplayMask(Mask ,RegexIRPrefixMask.ObserveMethod):D1}, {ObserveSource:D4}";
}
private int DisplayMask(
RegexIRPrefixMask mask,
RegexIRPrefixMask range
)
{
return range switch
{
RegexIRPrefixMask.ExeCondition => (int)(mask & RegexIRPrefixMask.ExeCondition) >> 0,
RegexIRPrefixMask.PopCondition => (int)(mask & RegexIRPrefixMask.PopCondition) >> 3,
RegexIRPrefixMask.ObserveMethod => (int)(mask & RegexIRPrefixMask.ObserveMethod) >> 5,
_ => throw new ArgumentOutOfRangeException(nameof(range), range, null)
};
}
}
}
+100 -47
View File
@@ -25,6 +25,7 @@
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -55,19 +56,6 @@ namespace StgSharp.RegularAnalysis.Text
}
internal enum RegexIRPrefix
{
Prev_Success = 1 << 0,
Prev_Fail = 1 << 1,
Always = 1 << 2,
ExeCondition = Prev_Fail | Prev_Success | Always,
Pop_Fail = 1 << 3,
Pop_Success = 1 << 4,
Pop_Condition = Pop_Success | Pop_Fail,
}
internal interface IRegexComplex
{
@@ -92,7 +80,10 @@ namespace StgSharp.RegularAnalysis.Text
}
internal sealed class RegexFindComplexIR(bool nearest, int count) : RegexIR, IRegexComplex
internal sealed class RegexFindComplexIR(
bool nearest,
int count
) : RegexIR, IRegexComplex
{
public bool IsFullyOptimized { get; set; }
@@ -103,9 +94,11 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Find_Complex;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t FIND_COMPLEX {(IsNearest ? "NEAREST" : "FURTHEST")} COUNT: {CommandCount}";
return $"FIND_COMPLEX {(IsNearest ? "NEAREST" : "FURTHEST")} COUNT: {CommandCount}";
}
}
@@ -113,13 +106,25 @@ namespace StgSharp.RegularAnalysis.Text
internal abstract class RegexIR
{
public RegexIRPrefix Prefix { get; set; }
internal abstract RegexIRCommand Command { get; }
internal abstract string AsCommand(int lineNum);
internal string AsCommand(
int lineNum
)
{
return $"[{lineNum}]\t{Prefix}\t{AsCommand()}";
}
protected abstract string AsCommand();
}
internal sealed class RegexFindSeqIR(string pattern, bool isFirst) : RegexIR
internal sealed class RegexFindSeqIR(
string pattern,
bool isFirst
) : RegexIR
{
public bool IsFirst { get; } = isFirst;
@@ -128,9 +133,10 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Find_Seq;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t FIND_SEQ \"{(string.IsNullOrEmpty(Pattern) ? "<EPSILON>" : Pattern)}\"";
return $"FIND_SEQ \"{(string.IsNullOrEmpty(Pattern) ? "<EPSILON>" : Pattern)}\"";
}
}
@@ -138,35 +144,46 @@ namespace StgSharp.RegularAnalysis.Text
/// <summary>
/// Searches for a certain string pattern or charset from current position.
/// </summary>
internal sealed class RegexMatchSeqIR(string pattern) : RegexIR
internal sealed class RegexMatchSeqIR(
string pattern
) : RegexIR
{
public string Pattern { get; } = pattern;
internal override RegexIRCommand Command => RegexIRCommand.Match_Seq;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t MATCH_SEQ \"{(string.IsNullOrEmpty(Pattern) ? "<EPSILON>" : Pattern)}\"";
return $"MATCH_SEQ \"{(string.IsNullOrEmpty(Pattern) ? "<EPSILON>" : Pattern)}\"";
}
}
internal sealed class RegexMatchSetIR(string charset) : RegexIR
internal sealed class RegexMatchSetIR(
string charset
) : RegexIR
{
public string Charset { get; } = charset;
internal override RegexIRCommand Command => RegexIRCommand.Match_Set;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t MATCH_SET \"{Charset}\"";
return $"MATCH_SET \"{Charset}\"";
}
}
internal sealed class RegexConditionIR(int success, int fail) : RegexIR
internal sealed class RegexConditionIR(
int success,
int fail
) : RegexIR
{
public int SuccessCase { get; } = success;
@@ -175,14 +192,19 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Condition;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t CONDITION SUCCESS: {SuccessCase} FAIL: {FailCase}";
return $"CONDITION SUCCESS: {SuccessCase} FAIL: {FailCase}";
}
}
internal sealed class RegexPackIR(bool condition, string name = "") : RegexIR
internal sealed class RegexPackIR(
bool condition,
string name = ""
) : RegexIR
{
public bool Condition { get; } = condition;
@@ -191,14 +213,21 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Pack;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t PACK {(Condition ? "SUCCESS" : "FAIL")} GROUP: \"{GroupName}\"";
return $"PACK {(Condition ? "SUCCESS" : "FAIL")} GROUP: \"{GroupName}\"";
}
}
internal sealed class RegexCountComplexIR(int min, int max, bool isGreedy, int operation) : RegexIR, IRegexCount, IRegexComplex
internal sealed class RegexCountComplexIR(
int min,
int max,
bool isGreedy,
int operation
) : RegexIR, IRegexCount, IRegexComplex
{
public bool IsGreedy { get; } = isGreedy;
@@ -217,14 +246,21 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command { get; } = RegexIRCommand.Count_Complex;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t COUNT {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} OPERATION: {CommandCount}";
return $"COUNT {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} OPERATION: {CommandCount}";
}
}
internal sealed class RegexCountSeqIR(int min, int max, bool isGreedy, string seq) : RegexIR, IRegexCount
internal sealed class RegexCountSeqIR(
int min,
int max,
bool isGreedy,
string seq
) : RegexIR, IRegexCount
{
public bool IsGreedy { get; } = isGreedy;
@@ -241,14 +277,21 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command { get; } = RegexIRCommand.Count_Seq;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t COUNT_SEQ {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} SEQ: \"{Sequence}\"";
return $"COUNT_SEQ {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} SEQ: \"{Sequence}\"";
}
}
internal sealed class RegexCountSetIR(int min, int max, bool isGreedy, string set) : RegexIR, IRegexCount
internal sealed class RegexCountSetIR(
int min,
int max,
bool isGreedy,
string set
) : RegexIR, IRegexCount
{
public bool IsGreedy { get; } = isGreedy;
@@ -267,14 +310,18 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Count_Set;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t COUNT_SET {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} SET: \"{CharSet}\"";
return $"COUNT_SET {(IsGreedy ? "GREEDY" : "NON_GREEDY")} MIN: {Min} MAX: {Max} SET: \"{CharSet}\"";
}
}
internal sealed class RegexTryIR(int count) : RegexIR, IRegexComplex
internal sealed class RegexTryIR(
int count
) : RegexIR, IRegexComplex
{
public bool IsFullyOptimized { get; set; }
@@ -283,23 +330,29 @@ namespace StgSharp.RegularAnalysis.Text
internal override RegexIRCommand Command => RegexIRCommand.Try;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t TRY {CommandCount}";
return $"TRY {CommandCount}";
}
}
internal sealed class RegexPopIR(bool isSuccess) : RegexIR
internal sealed class RegexPopIR(
bool isSuccess
) : RegexIR
{
public bool IsSuccess { get; } = isSuccess;
internal override RegexIRCommand Command => RegexIRCommand.Pop;
internal override string AsCommand(int lineNum)
protected override string AsCommand(
)
{
return $"[{lineNum}]\t POP {(IsSuccess ? "SUCCESS" : "FAIL")}";
return $"POP {(IsSuccess ? "SUCCESS" : "FAIL")}";
}
}