regex ir emitter is working

This commit is contained in:
Youmu Liu
2026-06-18 19:10:30 +08:00
parent 5570c6f338
commit eeca5721fb
5 changed files with 164 additions and 88 deletions
@@ -43,23 +43,21 @@ namespace StgSharp.RegularAnalysis.TextRegex
public partial class RegexInterpreter
{
private List<RegexIR> EmptyIR { get; } = [];
internal List<RegexIR> GenerateIR(
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree
internal static List<RegexIR> GenerateIR(
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree
)
{
return GenerateIRRecursion(tree.Root, 0).ToList();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EmitCount(
int curDepth,
RegexIRGenerator ir,
int min,
int max,
bool isGreedy,
RegexAstNode right
private static void EmitCount(
int curDepth,
RegexIRGenerator ir,
int min,
int max,
bool isGreedy,
RegexAstNode right
)
{
bool isRightOperator = !RegexAstNode.IsNullOrEmpty(right) &&
@@ -83,7 +81,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
ir.EmitCountSet(min, max, isGreedy, right.Source.Value);
break;
case RegexElementLabel.UNIT_SPAN:
ir.EmitCountSet(min, max, isGreedy, right.Source.Value);
ir.EmitCountSeq(min, max, isGreedy, right.Source.Value);
break;
default:
throw new InvalidOperationException($"Unexpected regex element type for count operator: {count_source_mask}");
@@ -91,9 +89,9 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
}
private RegexIRGenerator GenerateIRRecursion(
RegexAstNode node,
int depth
private static RegexIRGenerator GenerateIRRecursion(
RegexAstNode node,
int depth
)
{
#pragma warning disable IDE0010
@@ -107,11 +105,6 @@ namespace StgSharp.RegularAnalysis.TextRegex
RegexIRGenerator leftIR;
RegexIRGenerator rightIR;
bool isLeftOperator = !RegexAstNode.IsNullOrEmpty(left) &&
(left.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0;
bool isRightOperator = !RegexAstNode.IsNullOrEmpty(right) &&
(right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0;
Token<RegexElementLabel> token = node.Source;
switch (node.Source.Flag)
@@ -131,26 +124,41 @@ namespace StgSharp.RegularAnalysis.TextRegex
groupIR.EmitTry(rightIR.Count);
groupIR.EmitIRStream(rightIR);
groupIR.EmitCondition(2, 1);
groupIR.EmitPopLevel(false);
// a grouping op needed here, before popping
groupIR.EmitPopLevel(true);
/*generate pack ir here*/
return groupIR;
case RegexElementLabel.COUNT:
string count_source = token.Value;
bool isGreedy = !(count_source.Length > 1 && !count_source.EndsWith('?'));
bool isGreedy = !(count_source.Length > 1 && count_source.EndsWith('?'));
int seq_mask = (RegexAstNode.IsNullOrEmpty(left) ? 0 : 2) + (RegexAstNode.IsNullOrEmpty(right) ?
0 :
1);
RegexAstNode seq = seq_mask switch
{
// no seq, invalid count operator
0 => throw new InvalidOperationException("Count operator must have a sequence to operate on"),
// right seq
1 => right,
// left seq
2 => left,
// both sides, invalid count operator
3 => throw new InvalidOperationException("Count operator cannot have two sequences to operate on"),
_ => throw new InvalidOperationException("Unexpected sequence mask for count operator"),
};
ReadOnlySpan<char> count_source_span = count_source;
RegexIRGenerator countIR = new();
if (count_source_span[0] == '*') // infinite count
{
EmitCount(curDepth, countIR, 0, int.MaxValue, isGreedy, right);
EmitCount(curDepth, countIR, 0, int.MaxValue, isGreedy, seq);
} else if (count_source_span[0] == '+') // at least one
{
EmitCount(curDepth, countIR, 1, int.MaxValue, isGreedy, right);
EmitCount(curDepth, countIR, 1, int.MaxValue, isGreedy, seq);
} else if (count_source_span[0] == '?') // zero or one
{
EmitCount(curDepth, countIR, 0, 1, isGreedy, right);
EmitCount(curDepth, countIR, 0, 1, isGreedy, seq);
} else if (count_source_span[0] == '{') // zero or one, non-greedy
{
int comma_pos = count_source_span.IndexOf(',');
@@ -158,7 +166,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
{
if (int.TryParse(count_source[1..(isGreedy ? ^3 : ^2)], out int count))
{
EmitCount(curDepth, countIR, count, count, isGreedy, right);
EmitCount(curDepth, countIR, count, count, isGreedy, seq);
} else
{
throw new InvalidCastException($"Invalid count format: {count_source}");
@@ -168,7 +176,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
if (int.TryParse(count_source[1..comma_pos], out int min) &&
int.TryParse(count_source[(comma_pos + 1)..(isGreedy ? ^3 : ^2)], out int max))
{
EmitCount(curDepth, countIR, min, max, isGreedy, right);
EmitCount(curDepth, countIR, min, max, isGreedy, seq);
} else
{
throw new InvalidCastException($"Invalid count format: {count_source}");
@@ -192,7 +200,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
switch (left.Source.Flag)
{
case RegexElementLabel.UNIT_SPAN:
goto case RegexElementLabel.UNIT_SPAN;
goto case RegexElementLabel.UNIT;
case RegexElementLabel.UNIT:
concat.EmitMatchSeq(left.Source.Value);
break;
@@ -234,7 +242,40 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
return concat;
case RegexElementLabel.ALT:
return null!;
RegexIRGenerator alt = new();
List<RegexIRGenerator> casesIRList = [];
RegexAstNode cur_node = right;
int ir_count = 0;
while (!RegexAstNode.IsNullOrEmpty(cur_node))
{
RegexIRGenerator _case = GenerateIRRecursion(cur_node, curDepth + 1);
casesIRList.Add(_case);
ir_count += _case.Count;
cur_node = cur_node.Next;
}
int case_count = casesIRList.Count;
while (case_count != 0)
{
RegexIRGenerator cur_ir = casesIRList[^case_count];
ir_count -= cur_ir.Count;
case_count--;
alt.EmitTry(cur_ir.Count);
alt.EmitIRStream(cur_ir);
alt.EmitCondition(1/* need to calc here */, 2);
alt.EmitPop(true);
}
alt.EmitPop(false);
return alt;
case RegexElementLabel.UNIT_SPAN:
goto case RegexElementLabel.UNIT;
case RegexElementLabel.UNIT:
RegexIRGenerator unit_seq = new();
unit_seq.EmitMatchSeq(node.Source.Value);
return unit_seq;
case RegexElementLabel.UNIT_SET:
RegexIRGenerator unit_set = new();
unit_set.EmitMatchSet(node.Source.Value);
return unit_set;
default:
return null!;
}