a few changes on context
This commit is contained in:
@@ -227,7 +227,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
* [011] 0003, Sccs, DEF , LINE, 0010, PACK SUCCESS GROUP: "name"
|
||||
* [012] 0000, DEF , DEF , NONE, 0000, MATCH_SEQ "234"
|
||||
*/
|
||||
if (ir_span[0] is not RegexCountSetIR { IsDotStar: true } ||
|
||||
if (ir_span[0] is not RegexFindComplexIR { CommandCount: -1 } ||
|
||||
ir_span[1] is not RegexPackIR pack)
|
||||
{
|
||||
return -1;
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp;
|
||||
using StgSharp.RegularAnalysis.Abstraction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -117,24 +118,13 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
ReadOnlySpan<RegexIR> ir_sp = CollectionsMarshal.AsSpan(ir);
|
||||
|
||||
SequenceEmitter<string> match_e = new();
|
||||
int index = 0;
|
||||
int end = FindRegionEnd(ir_sp, index);
|
||||
ReadOnlySpan<RegexIR> region = ir_sp[0..end];
|
||||
|
||||
while (true)
|
||||
{
|
||||
// GenerateRegion(region, sc, match_e, sub_match_list);
|
||||
_ = TryGenerateAltChain(0, region, sc, match_e, sub_match_list);
|
||||
_ = TryGenerateTryBlock(0, region, sc, match_e, sub_match_list);
|
||||
_ = TryGenerateNamedCountAny(0, region, sc, match_e, sub_match_list);
|
||||
if (end >= ir_sp.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
index = end;
|
||||
end = FindRegionEnd(ir_sp, end);
|
||||
region = ir_sp[index..end];
|
||||
}
|
||||
sc.RegionExtent = MeasureRegionExtents(ir_sp, info.RegionCount);
|
||||
|
||||
// begin a very big do while(0)
|
||||
_ = se.AppendLine(sc.BeginRegion());
|
||||
|
||||
_ = GenerateBlock(0, ir_sp, sc, match_e, sub_match_list);
|
||||
|
||||
_ = se.AppendLine($@"public override MatchResult Match({ROS_char} text)")//
|
||||
.AppendLine(@"{");
|
||||
@@ -165,6 +155,11 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
|
||||
_ = se.Append(match_e);
|
||||
|
||||
// end of the biggest region
|
||||
_ = se.AppendLine(sc.CloseRegion());
|
||||
|
||||
// close the entire match result and return
|
||||
|
||||
foreach (SequenceEmitter<string> _sub in sub_match_list)
|
||||
{
|
||||
_ = se.AppendLine() //
|
||||
@@ -176,6 +171,82 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
return se;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursive dispatch entry. Walks one contiguous IR block and offers each window to the
|
||||
/// generators in descending consumption order. Region bodies, count bodies and find
|
||||
/// bodies recurse into this same method.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Total IR entries consumed, always <c> ir_span.Length </c>.
|
||||
/// </returns>
|
||||
private static int GenerateBlock(
|
||||
int outer_level,
|
||||
ReadOnlySpan<RegexIR> ir_span,
|
||||
SourceGenContext sc,
|
||||
in SequenceEmitter<string> code,
|
||||
in List<SequenceEmitter<string>> local_func
|
||||
)
|
||||
{
|
||||
int index = 0;
|
||||
while (index < ir_span.Length)
|
||||
{
|
||||
ReadOnlySpan<RegexIR> rest = ir_span[index..];
|
||||
|
||||
// ground entries pass one by one, a foreign region id opens a mountain;
|
||||
// carving always lands on a mountain head, so the extent is the carve length
|
||||
int id = rest[0].Prefix.WorkingRegion;
|
||||
int carve = id == outer_level ? 1 : sc.RegionExtent[id];
|
||||
Debug.Assert(id == outer_level || carve == FindRegionEnd(rest));
|
||||
|
||||
index += GenerateRegion(outer_level, rest[..carve], sc, code, local_func);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes exactly one carved region, or one ground instruction. Generators that own a
|
||||
/// body re-enter <see cref="GenerateBlock" />, which is what closes the recursion.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// IR entries consumed, at least 1.
|
||||
/// </returns>
|
||||
private static int GenerateRegion(
|
||||
int outer_level,
|
||||
ReadOnlySpan<RegexIR> region,
|
||||
SourceGenContext sc,
|
||||
in SequenceEmitter<string> code,
|
||||
in List<SequenceEmitter<string>> local_func
|
||||
)
|
||||
{
|
||||
int consumed;
|
||||
|
||||
// L1, several regions plus a tail
|
||||
if ((consumed = TryGenerateAltChain(outer_level, region, sc, code, local_func)) > 0) {
|
||||
return consumed;
|
||||
}
|
||||
if ((consumed = TryGenerateNamedCountAny(outer_level, region, sc, code,
|
||||
local_func)) > 0) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
// L2, one region
|
||||
if ((consumed = TryGenerateTryBlock(outer_level, region, sc, code, local_func)) > 0) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
// L4, single instruction fallback
|
||||
if ((consumed = TryGenerateSingleIR(outer_level, region, sc, code, local_func)) > 0) {
|
||||
return consumed;
|
||||
}
|
||||
if ((consumed = TryGeneratePack(outer_level, region, sc, code, local_func)) > 0) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
// unclaimed window must break the build of the generated file
|
||||
_ = code.AppendLine($@"#error NGRA has no source generation rule for {region[0]}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private enum RegionExitMethod
|
||||
@@ -188,18 +259,45 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
|
||||
#region shared helpers
|
||||
|
||||
// backward scan; the final write per id happens at its first entry, leaving full extent
|
||||
private static int[] MeasureRegionExtents(
|
||||
ReadOnlySpan<RegexIR> ir_sp,
|
||||
int regionCount
|
||||
)
|
||||
{
|
||||
int[] last_seen = new int[regionCount + 1];
|
||||
int[] extent = new int[regionCount + 1];
|
||||
Array.Fill(last_seen, -1);
|
||||
for (int i = ir_sp.Length - 1; i >= 0; i--)
|
||||
{
|
||||
int id = ir_sp[i].Prefix.WorkingRegion;
|
||||
if (last_seen[id] < 0) {
|
||||
last_seen[id] = i;
|
||||
}
|
||||
extent[id] = last_seen[id] - i + 1;
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int FindRegionEnd(
|
||||
ReadOnlySpan<RegexIR> ir_sp
|
||||
)
|
||||
{
|
||||
return FindRegionEnd(ir_sp, ir_sp[0].Prefix.WorkingRegion);
|
||||
}
|
||||
|
||||
// exclusive bound of the mountain opened at ir_sp[0], sub peaks included
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int FindRegionEnd(
|
||||
ReadOnlySpan<RegexIR> ir_sp,
|
||||
int current
|
||||
int level
|
||||
)
|
||||
{
|
||||
int cur_depth = ir_sp[current].Prefix.WorkingRegion;
|
||||
int end = ir_sp.Length;
|
||||
for (; end > 0; end--)
|
||||
for (int end = ir_sp.Length - 1; end > 0; end--)
|
||||
{
|
||||
if (ir_sp[end].Prefix.WorkingRegion == cur_depth) {
|
||||
return end;
|
||||
if (ir_sp[end].Prefix.WorkingRegion == level) {
|
||||
return end + 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -56,6 +56,9 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
|
||||
public string StepResult { get; } = _stepResult;
|
||||
|
||||
// region id -> entry count from first to last occurrence, filled once per pattern
|
||||
public int[] RegionExtent { get; set; } = [];
|
||||
|
||||
public string[] BeginRegion()
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user