add a merge tail alt operation

This commit is contained in:
Nitload
2026-06-16 00:23:43 +08:00
parent 861b50575a
commit 61b4c6012d
2 changed files with 55 additions and 71 deletions
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="RegexInterpreter.Optimize"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. 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
@@ -42,9 +42,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
public partial class RegexInterpreter
{
private static RegexAstNode FlattenAlt(
RegexAstNode root
)
private static RegexAstNode FlattenAlt(RegexAstNode root)
{
TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new(root);
List<RegexAstNode> cases = [];
@@ -69,9 +67,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
return cases[0];
}
private static bool MergeConcat(
RegexAstNode root
)
private static bool MergeConcat(RegexAstNode root)
{
if (root.EqualityTypeConvert != RegexElementLabel.CONCAT) {
return false;
@@ -113,8 +109,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
string str = left.Value;
buffer.Add(str);
length += str.Length;
while (!RegexAstNode.IsNullOrEmpty(right) &&
right.EqualityTypeConvert == RegexElementLabel.CONCAT)
while (!RegexAstNode.IsNullOrEmpty(right) && right.EqualityTypeConvert == RegexElementLabel.CONCAT)
{
left = right.Left;
if (left.EqualityTypeConvert is not RegexElementLabel.UNIT_SPAN and
@@ -137,10 +132,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
buffer.Add(right.Value);
length += right.Value.Length;
}
str = string.Create(length, buffer, static(
span,
buffer
) => {
str = string.Create(length, buffer, static(span, buffer) => {
int offset = 0;
for (int i = 0; i < buffer.Count; i++)
{
@@ -148,21 +140,17 @@ namespace StgSharp.RegularAnalysis.TextRegex
offset += buffer[i].Length;
}
});
root.Left = new RegexAstNode(new Token<RegexElementLabel>(str, left.Source.Line,
left.Source.Column,
root.Left = new RegexAstNode(new Token<RegexElementLabel>(str, left.Source.Line, left.Source.Column,
str.Length == 1 ?
RegexElementLabel.UNIT :
RegexElementLabel.UNIT_SPAN));
return true;
}
private static void RotateConcat(
RegexAstNode root
)
private static void RotateConcat(RegexAstNode root)
{
RegexAstNode left = root.Left;
while (!RegexAstNode.IsNullOrEmpty(left) &&
left.EqualityTypeConvert == RegexElementLabel.CONCAT)
while (!RegexAstNode.IsNullOrEmpty(left) && left.EqualityTypeConvert == RegexElementLabel.CONCAT)
{
/*
* root → root
@@ -205,13 +193,10 @@ namespace StgSharp.RegularAnalysis.TextRegex
///
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static RegexAstNode MergeAlt(
List<RegexAstNode> cases
)
private static RegexAstNode MergeAlt(List<RegexAstNode> cases)
{
UnionAlt union = new(0, cases);
RegexAstNode root = union.AsNormal();
return root;
}
@@ -220,10 +205,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
private const int MaxLevel = 8;
private UnionAlt(
int level,
RegexAstNode node
)
private UnionAlt(int level, RegexAstNode node)
: base(node.Source)
{
Level = level;
@@ -231,8 +213,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
RegexAstNode right = IsNullOrEmpty(node.Right) ?
new RegexAstNode(
new Token<RegexElementLabel>(node.Value, 0, node.Source.Column,
RegexElementLabel.UNIT)
new Token<RegexElementLabel>(node.Value, 0, node.Source.Column, RegexElementLabel.UNIT)
) :
node.Right;
Cases.Add(right);
@@ -243,10 +224,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
UnionEnd = node;
}
public UnionAlt(
int level,
List<RegexAstNode> c
)
public UnionAlt(int level, List<RegexAstNode> c)
: base(c[0].Source)
{
Cases = c;
@@ -273,11 +251,11 @@ namespace StgSharp.RegularAnalysis.TextRegex
{
if ((Cases[i].EqualityTypeConvert & RegexElementLabel.SEQUENCE) != 0)
{
RegexAstNode concat = new RegexAstNode(new Token<RegexElementLabel>(string.Empty,
0,
Cases[i].Source.Column,
RegexElementLabel.CONCAT));
concat.Left = Cases[i];
RegexAstNode concat = new(new Token<RegexElementLabel>(string.Empty, 0, Cases[i].Source.Column,
RegexElementLabel.CONCAT))
{
Left = Cases[i]
};
Cases[i].Parent = concat;
concat.Right = Empty;
Cases[i] = concat;
@@ -345,15 +323,13 @@ namespace StgSharp.RegularAnalysis.TextRegex
RegexAstNode branch;
if (IsNullOrEmpty(UnionEnd))
{
branch = new RegexAstNode(new Token<RegexElementLabel>(string.Empty, 0,
Source.Column,
branch = new RegexAstNode(new Token<RegexElementLabel>(string.Empty, 0, Source.Column,
RegexElementLabel.ALT));
UnionBegin = branch;
UnionEnd = branch;
} else
{
branch = new RegexAstNode(new Token<RegexElementLabel>(string.Empty, 0,
UnionEnd.Source.Column,
branch = new RegexAstNode(new Token<RegexElementLabel>(string.Empty, 0, UnionEnd.Source.Column,
RegexElementLabel.ALT));
UnionEnd.Right = branch;
branch.Parent = UnionEnd;
@@ -370,23 +346,17 @@ namespace StgSharp.RegularAnalysis.TextRegex
return UnionBegin;
}
private void AddCase(
RegexAstNode _case
)
private void AddCase(RegexAstNode _case)
{
RegexAstNode right = IsNullOrEmpty(_case.Right) ?
new RegexAstNode(
new Token<RegexElementLabel>(_case.Value, 0, _case.Source.Column,
RegexElementLabel.UNIT)
new Token<RegexElementLabel>(_case.Value, 0, _case.Source.Column, RegexElementLabel.UNIT)
) :
_case.Right;
Cases.Add(right);
}
private static bool CanMerge(
RegexAstNode origin,
RegexAstNode target
)
private static bool CanMerge(RegexAstNode origin, RegexAstNode target)
{
// suppose that origin is not a union,
if (target is UnionAlt alt)
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="RegexInterpreter"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. 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
@@ -58,9 +58,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
}
public static RegexInterpreter Analyze(
string regex
)
public static RegexInterpreter Analyze(string regex)
{
RegexInterpreter interpreter = new();
interpreter._source = regex;
@@ -166,8 +164,8 @@ namespace StgSharp.RegularAnalysis.TextRegex
)
{
// phase0: scan container and remove no parent nodes
_tree.AllNodes.RemoveWhere(node => node.Parent == null && node != _tree.Root);
TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new TreeEnumerator<RegexAstNode, RegexElementLabel>(_tree.Root);
_ = _tree.AllNodes.RemoveWhere(node => node.Parent == null && node != _tree.Root);
TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new(_tree.Root);
RegexAstNode current;
// phase1: ALT flatten
@@ -179,10 +177,30 @@ namespace StgSharp.RegularAnalysis.TextRegex
current = enumerator.Current;
if (current.EqualityTypeConvert == RegexElementLabel.ALT)
{
RegexAstNode union = FlattenAlt(current);
altNodes.Add(current);
current.Right = union;
current.Left = RegexAstNode.Empty;
if (current.Left.EqualityTypeConvert == RegexElementLabel.UNIT &&
current.Right.EqualityTypeConvert == RegexElementLabel.UNIT)
{
if (string.IsNullOrEmpty(current.Left.Value))
{
// TODO replace the alt node with a count node
/*
RegexAstNode parent = current.Parent;
parent.Next = new RegexAstNode();
/**/
} else if (string.IsNullOrEmpty(current.Right.Value))
{
// TODO replace the alt node with a count node
} else
{
// TODO replace the alt node with a charset node
}
} else
{
RegexAstNode union = FlattenAlt(current);
altNodes.Add(current);
current.Right = union;
current.Left = RegexAstNode.Empty;
}
} else if (current.EqualityTypeConvert == RegexElementLabel.CONCAT) {
RotateConcat(current);
}
@@ -221,14 +239,11 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
}
private void ProcessOperator(
RegexAstNode op
)
private void ProcessOperator(RegexAstNode op)
{
if (op.EqualityTypeConvert == RegexElementLabel.CONCAT)
{
if (_stack.TryPopOperand(out RegexAstNode? _1) &&
_stack.TryPopOperand(out RegexAstNode? _2))
if (_stack.TryPopOperand(out RegexAstNode? _1) && _stack.TryPopOperand(out RegexAstNode? _2))
{
op.Left = _2;
op.Right = _1;
@@ -254,8 +269,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
} else if (op.EqualityTypeConvert == RegexElementLabel.ALT)
{
if (_stack.TryPopOperand(out RegexAstNode? _1) &&
_stack.TryPopOperand(out RegexAstNode? _2))
if (_stack.TryPopOperand(out RegexAstNode? _1) && _stack.TryPopOperand(out RegexAstNode? _2))
{
op.Left = _2;
op.Right = _1;