add single ir generator methods
This commit is contained in:
@@ -13,36 +13,6 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
{
|
{
|
||||||
internal partial class TextRegexSourceGen
|
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
|
* L4, one instruction
|
||||||
@@ -104,6 +74,75 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
* already expressed by its execution condition.
|
* 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(
|
private static int TryGenerateMatchSeq(
|
||||||
int outer_level,
|
int outer_level,
|
||||||
ReadOnlySpan<RegexIR> ir_span,
|
ReadOnlySpan<RegexIR> ir_span,
|
||||||
@@ -117,10 +156,10 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
}
|
}
|
||||||
string seq = match_seq.Pattern;
|
string seq = match_seq.Pattern;
|
||||||
string literal = FormatStringLiteral(seq);
|
string literal = FormatStringLiteral(seq);
|
||||||
_ = code.AppendLine(@$"if({sc.InputSpan}[{sc.Cursor}..].StartWith(""{literal}""))")
|
_ = code.AppendLine(@$"if({sc.InputSpan}[{sc.Position}..].StartWith({literal}))")
|
||||||
.AppendLine("{")
|
.AppendLine("{")
|
||||||
.AppendLine($"{sc.StepResult} = true;")
|
.AppendLine($"{sc.StepResult} = true;")
|
||||||
.AppendLine($@"{sc.Cursor} += {seq.Length};")
|
.AppendLine($@"{sc.Position} += {seq.Length};")
|
||||||
.AppendLine("}");
|
.AppendLine("}");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -139,62 +178,76 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
string set_source = match_set.Charset;
|
string set_source = match_set.Charset;
|
||||||
RegexCharSet[] set_arr = FigureCharSetType(set_source, out bool accept);
|
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++)
|
for (int i = 1; i < set_arr.Length - 1; i++)
|
||||||
{
|
{
|
||||||
RegexCharSet set = set_arr[i];
|
set = set_arr[i];
|
||||||
switch (set.Type)
|
_case_code = GenLine(set, sc, "||");
|
||||||
{
|
_ = code.AppendLine(_case_code);
|
||||||
case CharSetType.Single:
|
|
||||||
string cases = set.Value;
|
|
||||||
if (cases.Length > 8)
|
|
||||||
{
|
|
||||||
// more than 8 different chars, using string match
|
|
||||||
string literal = FormatStringLiteral(cases);
|
|
||||||
_ = code.AppendLine($@"{literal}.Contains({sc.InputSpan}[{sc.Cursor}])");
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
StringBuilder sb = new();
|
|
||||||
_ = sb.Append('(');
|
|
||||||
for (int j = 0; j < cases.Length - 1; j++) {
|
|
||||||
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Cursor}] == {cases[j]} ||");
|
|
||||||
}
|
|
||||||
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Cursor}] == {cases[^1]}")
|
|
||||||
.Append(")||");
|
|
||||||
_ = code.AppendLine(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;
|
|
||||||
case CharSetType.Set:
|
|
||||||
string accept_mark = set.Accept ? string.Empty : "!";
|
|
||||||
switch (set.Value)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
case CharSetType.None:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
set = set_arr[^1];
|
||||||
|
_case_code = GenLine(set, sc, ")");
|
||||||
|
_ = code.AppendLine(_case_code)
|
||||||
|
.AppendLine("{")
|
||||||
|
.AppendLine("-------------------------------------")// TODO case success
|
||||||
|
.AppendLine("}");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GenLine(
|
||||||
|
RegexCharSet set,
|
||||||
|
SourceGenContext sc,
|
||||||
|
string end_of_line
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (set.Type)
|
||||||
|
{
|
||||||
|
case CharSetType.Single:
|
||||||
|
string cases = set.Value;
|
||||||
|
if (cases.Length > 8)
|
||||||
|
{
|
||||||
|
// more than 8 different chars, using string match
|
||||||
|
string literal = FormatStringLiteral(cases);
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
literal = FormatCharLiteral(cases[j]);
|
||||||
|
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Position}] == {literal} ||");
|
||||||
|
}
|
||||||
|
literal = FormatCharLiteral(cases[^1]);
|
||||||
|
_ = sb.Append(CultureInfo.InvariantCulture, $@"{sc.InputSpan}[{sc.Position}] == {literal}")
|
||||||
|
.Append(CultureInfo.InvariantCulture, @$") {end_of_line}");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
case CharSetType.Range:
|
||||||
|
string rule = set.Value;
|
||||||
|
char lo = rule[0];
|
||||||
|
char hi = rule[1];
|
||||||
|
return $@"({sc.InputSpan}[{sc.Position}] >= '{lo}' && {sc.InputSpan}[{sc.Position}] <= '{hi}') {end_of_line}";
|
||||||
|
|
||||||
|
case CharSetType.Set:
|
||||||
|
string accept_mark = set.Accept ? string.Empty : "!";
|
||||||
|
return set.Value switch
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
return string.Empty;
|
||||||
|
default:
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,11 +48,13 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
private readonly HashSet<int> _observedLines = [];
|
private readonly HashSet<int> _observedLines = [];
|
||||||
|
|
||||||
private int _anonymousGroup;
|
private int _anonymousGroup;
|
||||||
|
|
||||||
|
private int _count_idx = 0;
|
||||||
private int _scratchIndex;
|
private int _scratchIndex;
|
||||||
private readonly SortedSet<int> _lineSlots = [];
|
private readonly SortedSet<int> _lineSlots = [];
|
||||||
private readonly SortedSet<int> _regionSlots = [];
|
private readonly SortedSet<int> _regionSlots = [];
|
||||||
|
|
||||||
public string Cursor { get; } = _cursor;
|
public string Position { get; } = _cursor;
|
||||||
|
|
||||||
public string InputSpan { get; } = _inputSpan;
|
public string InputSpan { get; } = _inputSpan;
|
||||||
|
|
||||||
@@ -179,6 +181,13 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
return $"__r{region}_ok";
|
return $"__r{region}_ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string RequireNewCounter()
|
||||||
|
{
|
||||||
|
string counter_name = $"__count{_count_idx}";
|
||||||
|
_count_idx++;
|
||||||
|
return counter_name;
|
||||||
|
}
|
||||||
|
|
||||||
private int ResolveGroup(
|
private int ResolveGroup(
|
||||||
string name
|
string name
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user