add single ir generator methods

This commit is contained in:
Youmu Liu
2026-08-04 18:04:31 +08:00
parent 029092b438
commit 00e0d84603
2 changed files with 146 additions and 84 deletions
@@ -13,36 +13,6 @@ namespace StgSharp.RegularAnalysis.Text
{
internal partial class TextRegexSourceGen
{
private static int TryGenerateCountSeq(
int outer_level,
ReadOnlySpan<RegexIR> ir_span,
SourceGenContext sc,
in SequenceEmitter<string> code,
in List<SequenceEmitter<string>> local_func
)
{
if (ir_span[0] is not RegexCountSeqIR count_seq) {
return -1;
}
string seq = count_seq.Pattern;
string literal = FormatStringLiteral(seq);
bool is_greedy = count_seq.IsGreedy;
int min = count_seq.Min;
int max = count_seq.Max;
int leave = is_greedy ? min : max;
// TODO cannot check real count outside the cycle
_ = code.AppendLine(@$"for(int count = 0; count<{leave}; count++)")
.AppendLine("{")
.AppendLine(@$"if({sc.InputSpan}[{sc.Cursor}..].StartWith(""{literal}""))")
.AppendLine("{")
.AppendLine(@$"{sc.Cursor}+={seq.Length};")
.AppendLine("}")
.AppendLine("}");
return 1;
}
/*
* =======================================================================================
* L4, one instruction
@@ -104,6 +74,75 @@ namespace StgSharp.RegularAnalysis.Text
* already expressed by its execution condition.
*/
#region code
private static int TryGenerateCountSet(
int outer_level,
ReadOnlySpan<RegexIR> ir_span,
SourceGenContext sc,
in SequenceEmitter<string> code,
in List<SequenceEmitter<string>> local_func
)
{
if (ir_span[0] is not RegexCountSetIR count_set) {
return -1;
}
string set_source = count_set.CharSet;
RegexCharSet[] set_arr = FigureCharSetType(set_source, out bool accept);
_ = code.AppendLine(accept ? @$"if(" : @$"if(!(");
string _case_code;
RegexCharSet set;
for (int i = 1; i < set_arr.Length - 1; i++)
{
set = set_arr[i];
_case_code = GenLine(set, sc, "||");
_ = code.AppendLine(_case_code);
}
set = set_arr[^1];
_case_code = GenLine(set, sc, ")");
_ = code.AppendLine(_case_code)
.AppendLine("{")
.AppendLine("-------------------------------------")// TODO case success
.AppendLine("}");
return 1;
}
private static int TryGenerateCountSeq(
int outer_level,
ReadOnlySpan<RegexIR> ir_span,
SourceGenContext sc,
in SequenceEmitter<string> code,
in List<SequenceEmitter<string>> local_func
)
{
if (ir_span[0] is not RegexCountSeqIR count_seq) {
return -1;
}
string seq = count_seq.Pattern;
string literal = FormatStringLiteral(seq);
bool is_greedy = count_seq.IsGreedy;
int min = count_seq.Min;
int max = count_seq.Max;
int leave = is_greedy ? max : min;
string counter = sc.RequireNewCounter();
// TODO cannot check real count outside the cycle
_ = code.AppendLine($@"int {counter} = 0;")
.AppendLine(@$"for(; {counter}<{leave}; {counter}++)")
.AppendLine("{")
.AppendLine(@$"if({sc.InputSpan}[{sc.Position}..].StartWith({literal}))")
.AppendLine("{")
.AppendLine(@$"{sc.Position}+={seq.Length};")
.AppendLine("}")
.AppendLine("}")
.AppendLine()
.AppendLine(@$"if({counter}>{min})") // TODO match here
.AppendLine($@"else"); // TODO fail here
return 1;
}
private static int TryGenerateMatchSeq(
int outer_level,
ReadOnlySpan<RegexIR> ir_span,
@@ -117,10 +156,10 @@ namespace StgSharp.RegularAnalysis.Text
}
string seq = match_seq.Pattern;
string literal = FormatStringLiteral(seq);
_ = code.AppendLine(@$"if({sc.InputSpan}[{sc.Cursor}..].StartWith(""{literal}""))")
_ = code.AppendLine(@$"if({sc.InputSpan}[{sc.Position}..].StartWith({literal}))")
.AppendLine("{")
.AppendLine($"{sc.StepResult} = true;")
.AppendLine($@"{sc.Cursor} += {seq.Length};")
.AppendLine($@"{sc.Position} += {seq.Length};")
.AppendLine("}");
return 1;
}
@@ -139,10 +178,30 @@ namespace StgSharp.RegularAnalysis.Text
string set_source = match_set.Charset;
RegexCharSet[] set_arr = FigureCharSetType(set_source, out bool accept);
_ = code.AppendLine(@$"if(");
_ = code.AppendLine(accept ? @$"if(" : @$"if(!(");
string _case_code;
RegexCharSet set;
for (int i = 1; i < set_arr.Length - 1; i++)
{
RegexCharSet set = set_arr[i];
set = set_arr[i];
_case_code = GenLine(set, sc, "||");
_ = code.AppendLine(_case_code);
}
set = set_arr[^1];
_case_code = GenLine(set, sc, ")");
_ = code.AppendLine(_case_code)
.AppendLine("{")
.AppendLine("-------------------------------------")// TODO case success
.AppendLine("}");
return 1;
}
private static string GenLine(
RegexCharSet set,
SourceGenContext sc,
string end_of_line
)
{
switch (set.Type)
{
case CharSetType.Single:
@@ -151,50 +210,44 @@ namespace StgSharp.RegularAnalysis.Text
{
// more than 8 different chars, using string match
string literal = FormatStringLiteral(cases);
_ = code.AppendLine($@"{literal}.Contains({sc.InputSpan}[{sc.Cursor}])");
return $@"{literal}.Contains({sc.InputSpan}[{sc.Position}]) {end_of_line}";
} else
{
StringBuilder sb = new();
string literal;
_ = sb.Append('(');
for (int j = 0; j < cases.Length - 1; j++) {
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Cursor}] == {cases[j]} ||");
for (int j = 0; j < cases.Length - 1; j++)
{
literal = FormatCharLiteral(cases[j]);
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Position}] == {literal} ||");
}
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Cursor}] == {cases[^1]}")
.Append(")||");
_ = code.AppendLine(sb.ToString());
literal = FormatCharLiteral(cases[^1]);
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Position}] == {literal}")
.Append(CultureInfo.InvariantCulture, @$") {end_of_line}");
return sb.ToString();
}
break;
case CharSetType.Range:
string rule = set.Value;
char lo = rule[0];
char hi = rule[1];
_ = code.AppendLine($@"({sc.InputSpan}[{sc.Cursor}] >= '{lo}' && {sc.InputSpan}[{sc.Cursor}] <= '{hi}') ||");
break;
return $@"({sc.InputSpan}[{sc.Position}] >= '{lo}' && {sc.InputSpan}[{sc.Position}] <= '{hi}') {end_of_line}";
case CharSetType.Set:
string accept_mark = set.Accept ? string.Empty : "!";
switch (set.Value)
return set.Value switch
{
case "s":
_ = code.AppendLine($@"{accept_mark}char.IsWhiteSpace({sc.InputSpan}[{sc.Cursor}]) ||");
break;
case "d":
_ = code.AppendLine($@"{accept_mark}char.IsDigit({sc.InputSpan}[{sc.Cursor}]) ||");
break;
case "w":
_ = code .AppendLine($@"{accept_mark}IsCharWord({sc.InputSpan}[{sc.Cursor}]) ||");
break;
default:
break;
}
break;
"s" => $@"{accept_mark}char.IsWhiteSpace({sc.InputSpan}[{sc.Position}]) {end_of_line}",
"d" => $@"{accept_mark}char.IsDigit({sc.InputSpan}[{sc.Position}]) {end_of_line}",
"w" => $@"{accept_mark}IsCharWord({sc.InputSpan}[{sc.Position}]) {end_of_line}",
_ => string.Empty
};
case CharSetType.None:
break;
return string.Empty;
default:
break;
return string.Empty;
}
}
return 1;
}
#endregion
}
}
@@ -48,11 +48,13 @@ namespace StgSharp.RegularAnalysis.Text
private readonly HashSet<int> _observedLines = [];
private int _anonymousGroup;
private int _count_idx = 0;
private int _scratchIndex;
private readonly SortedSet<int> _lineSlots = [];
private readonly SortedSet<int> _regionSlots = [];
public string Cursor { get; } = _cursor;
public string Position { get; } = _cursor;
public string InputSpan { get; } = _inputSpan;
@@ -179,6 +181,13 @@ namespace StgSharp.RegularAnalysis.Text
return $"__r{region}_ok";
}
public string RequireNewCounter()
{
string counter_name = $"__count{_count_idx}";
_count_idx++;
return counter_name;
}
private int ResolveGroup(
string name
)