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