From 8641fd4e087626ec8956c93ade74c3535bbba5f4 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Tue, 8 Sep 2026 18:10:36 +0800 Subject: [PATCH] Small changeds on text regex source gen --- .../Text/TextRegexSourceGen.ExitLabel.cs | 11 +++++ .../Text/TextRegexSourceGen.GenClass.cs | 40 ++++++++++--------- .../Text/TextRegexSourceGen.GenContext.cs | 14 +++---- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.ExitLabel.cs b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.ExitLabel.cs index 9be0c251..766bd8e7 100644 --- a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.ExitLabel.cs +++ b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.ExitLabel.cs @@ -41,6 +41,17 @@ namespace Nitload.RegularAnalysis.Text public int LabelOrder { get; init; } + public string GetLabelName() + { + return Mode switch + { + ExitMode.Break => $@"__break_{LabelOrder}", + ExitMode.Continue => $@"__continue_{LabelOrder}", + ExitMode.Goto => $@"__goto_{LabelOrder}", + _ => throw new NotImplementedException(), + }; + } + } } diff --git a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs index a5cdebcb..14958b43 100644 --- a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs +++ b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs @@ -183,9 +183,10 @@ namespace Nitload.RegularAnalysis.Text ) { RegexAstNode current = node.Right; + // TODO(NGRA-NAMING): Reserve exclusive names for future ALT cursor/capture snapshots; // their lifetime extends through retry labels, not just the candidate's emitted block. - string exit_label = context.RequestExitLabel(); + ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto); // TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal // shape and failure continuation are not wired yet. @@ -350,7 +351,7 @@ namespace Nitload.RegularAnalysis.Text bool is_greedy, [NotNull] in SequenceEmitter sc, in SourceGenContext context, - string exit_label + in ExitLabel exit ) { if (min < 0 || (max >= 0 && max < min)) { @@ -366,9 +367,11 @@ namespace Nitload.RegularAnalysis.Text char expected = literal[0]; string expected_literal = FormatCharLiteral(expected); string remain_span = context.RemainSpan; + // TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index, // and additional_count through the exclusive-name pool, including loop-local names. int scratch_scope_index = context.RequestScratchScopeIndex(); + string exit_label_node = exit.GetLabelName(); string required_rest = $"__required_rest_{scratch_scope_index}"; string required_matched = $"__required_matched_{scratch_scope_index}"; string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}"; @@ -384,7 +387,7 @@ namespace Nitload.RegularAnalysis.Text string required_prefix = new(expected, min); _ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(required_prefix)}))") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{remain_span} = {remain_span}.Slice({min});"); } @@ -399,7 +402,7 @@ namespace Nitload.RegularAnalysis.Text _ = sc.AppendLine($"if ({remain_span}.Length < {min})") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{ROS_char} {required_rest} = {remain_span};") .AppendLine($"bool {required_matched} = true;") @@ -424,7 +427,7 @@ namespace Nitload.RegularAnalysis.Text _ = sc.AppendLine($"if (!{required_matched})") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{remain_span} = {remain_span}.Slice({min});"); } @@ -451,7 +454,6 @@ namespace Nitload.RegularAnalysis.Text // a future continuation attempt fails and requests another repetition. _ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation."); } - } private static void GenerateUnitSetCount( @@ -460,7 +462,8 @@ namespace Nitload.RegularAnalysis.Text int max, bool is_greedy, [NotNull] in SequenceEmitter sc, - in SourceGenContext context + in SourceGenContext context, + in ExitLabel exit_label ) { if (min < 0 || (max >= 0 && max < min)) { @@ -477,6 +480,7 @@ namespace Nitload.RegularAnalysis.Text IReadOnlyList charset = payload.Set; string remain_span = context.RemainSpan; + // TODO(NGRA-NAMING): Allocate required_matched and additional_count through the // exclusive-name pool. Reserve required_rest/required_chunk_index if emitted later. int scratch_scope_index = context.RequestScratchScopeIndex(); @@ -533,7 +537,7 @@ namespace Nitload.RegularAnalysis.Text bool is_greedy, [NotNull] in SequenceEmitter sc, in SourceGenContext context, - string exit_label + in ExitLabel exit ) { if (min < 0 || (max >= 0 && max < min)) { @@ -548,10 +552,12 @@ namespace Nitload.RegularAnalysis.Text string expected_literal = FormatStringLiteral(literal); string remain_span = context.RemainSpan; + // TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index, // required_count, and additional_count through the exclusive-name pool. Flattened // sibling COUNT nodes share the declaration space even after their exit labels. int scratch_scope_index = context.RequestScratchScopeIndex(); + string exit_label_node = exit.GetLabelName(); string required_rest = $"__required_rest_{scratch_scope_index}"; string required_matched = $"__required_matched_{scratch_scope_index}"; string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}"; @@ -575,7 +581,7 @@ namespace Nitload.RegularAnalysis.Text .AppendLine("}") .AppendLine($"if ({required_count} != {min})") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{remain_span} = {required_rest};"); } else if (min <= flattened_unit_count_threshold / literal.Length) @@ -589,7 +595,7 @@ namespace Nitload.RegularAnalysis.Text string required_prefix = required_prefix_span.ToString(); _ = sc.AppendLine($"if (!{remain_span}.{starts_with}({FormatStringLiteral(required_prefix)}))") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{remain_span} = {remain_span}.Slice({min * literal.Length});"); } @@ -638,7 +644,7 @@ namespace Nitload.RegularAnalysis.Text _ = sc.AppendLine($"if (!{required_matched})") .AppendLine("{") - .AppendLine($"goto {exit_label};") + .AppendLine($"goto {exit_label_node};") .AppendLine("}") .AppendLine($"{remain_span} = {required_rest};"); } @@ -665,14 +671,14 @@ namespace Nitload.RegularAnalysis.Text // a future continuation attempt fails and requests another repetition. _ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation."); } - } private static void GenerateCount( RegexAstNode node, [NotNull] in SequenceEmitter sc, in List> func_list, - in SourceGenContext context + in SourceGenContext context, + in ExitLabel exit ) { RegexAstNode value = RegexAstNode.IsNullOrEmpty(node.Left) ? node.Right : node.Left; @@ -683,9 +689,10 @@ namespace Nitload.RegularAnalysis.Text int min = payload.Min; int max = payload.Max; bool is_greedy = payload.IsGreedy; + // TODO(NGRA-NAMING): Reserve exclusive names for future repetition/rollback state // across complex COUNT retries; recursive children must use the same method pool. - string exit_label = context.RequestExitLabel(); + ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto); if ((value.Label & RegexElementLabel.SEQUENCE) == 0) { // TODO(NGRA): Emit min/max repetition, zero-width progress protection, greedy vs. @@ -699,10 +706,7 @@ namespace Nitload.RegularAnalysis.Text GenerateUnitCount(value, min, max, is_greedy, sc, context, exit_label); break; case RegexElementLabel.UNIT_SET: - GenerateUnitSetCount(value, min, max, is_greedy, sc, context); - - // TODO(NGRA): Emit a bounded/unbounded charset counting loop, preferably - // using IndexOfAnyExcept where the charset shape permits it. + GenerateUnitSetCount(value, min, max, is_greedy, sc, context, exit_label); break; case RegexElementLabel.UNIT_SPAN: GenerateUnitSpanCount(value, min, max, is_greedy, sc, context, exit_label); diff --git a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenContext.cs b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenContext.cs index fd860735..b7642b11 100644 --- a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenContext.cs +++ b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenContext.cs @@ -36,7 +36,7 @@ namespace Nitload.RegularAnalysis.Text public const string _remain_span = "__remain"; - private int _exit_alt_count; + private int _max_exit_lable; private int _scratch_scope_count; @@ -53,13 +53,13 @@ namespace Nitload.RegularAnalysis.Text return sc.AppendLine($@"{ROS_char} {RemainSpan};"); } - public string RequestExitLabel() + public ExitLabel RequestExitLabel( + ExitMode exitMode + ) { - // TODO(NGRA-NAMING): Route ALT and COUNT labels through the method-wide label pool. - // Keep every emitted label exclusive until method generation is complete. - string code = $@"_exit_alt_{_exit_alt_count}"; - _exit_alt_count++; - return code; + int index = _max_exit_lable; + _max_exit_lable++; + return new(exitMode, index); } public int RequestScratchScopeIndex()