add a merge tail alt operation
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user