add more rules for ir opt, fix wrong process to dot

This commit is contained in:
Youmu Liu
2026-07-03 18:05:10 +08:00
parent 8c504a67d7
commit 7edb94943d
13 changed files with 200 additions and 52 deletions
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="CharSetEmitter"
// file="RegexAnalyzerBackEnd.CharSetEmitter"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
@@ -44,7 +44,7 @@ namespace StgSharp.RegularAnalysis.Text
}
internal record struct CharSet(
internal record struct RegexCharSet(
string value,
CharSetType t,
bool accept
@@ -57,13 +57,18 @@ namespace StgSharp.RegularAnalysis.Text
public string Value { get; set; } = value;
public override readonly string ToString()
{
return $"{{value:{value}, type:{Type}, accept:{IsAcceptable}}}";
}
}
internal class CharSetEmitter
internal static partial class RegexAnalyzerBackEnd
{
public static CharSet[] FigureCharSetType(
ReadOnlySpan<char> source
public static RegexCharSet[] FigureCharSetType(
ReadOnlySpan<char> source
)
{
// range or single
@@ -76,19 +81,24 @@ namespace StgSharp.RegularAnalysis.Text
ReadOnlySpan<char> seq = source.Slice(idx, source.Length - idx - 1);
if (seq.IndexOf('-') == -1)
{
return [new CharSet(seq.ToString(), CharSetType.Single, accept)];
return [new RegexCharSet(seq.ToString(), CharSetType.Single, accept)];
} else
{
List<CharSet> list = [];
for (int i = 0; i < seq.Length && seq.Length > 0; )
List<RegexCharSet> list = [];
for (; seq.Length > 0; )
{
int pos = seq.IndexOf('-');
if (pos == -1)
{
RegexCharSet single = new(seq.ToString(), CharSetType.Single, accept);
list.Add(single);
break;
} else
if (pos > 1) {
list.Add(new(seq[0..(pos - 1)].ToString(), CharSetType.Single, accept));
}
list.Add(new($"{seq[pos - 1]}{seq[pos + 1]}", CharSetType.Range, accept));
i = pos + 2;
seq = seq[i..];
seq = seq[(pos + 2)..];
}
return [.. list];
}
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexInterpreter.SourceGenerate"
// file="RegexAnalyzerBackEnd"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
@@ -25,6 +25,7 @@
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -33,19 +34,14 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
internal static partial class RegexAnalyzerBackEnd
{
internal static string GetSourceCode(
IEnumerable<RegexIR> irs
internal static string GenerateSource(
List<RegexIR> ir
)
{
StringBuilder sb = new StringBuilder();
foreach (RegexIR ir in irs)
{
// ScanAndMarkIROptimization(ir);
}
return sb.ToString();
return string.Empty;
}
}
@@ -35,7 +35,7 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
public partial class RegexAnalyzerFrontEnd
{
private static AbstractSyntaxTree<RegexAstNode, RegexElementLabel> GenerateAST(
@@ -39,7 +39,7 @@ using System.Xml.Linq;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
public partial class RegexAnalyzerFrontEnd
{
private static RegexAstNode FlattenAlt(
@@ -40,7 +40,7 @@ using System.Xml;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
public partial class RegexAnalyzerFrontEnd
{
internal static List<RegexIR> GenerateIR(
@@ -1,6 +1,6 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexAnalyzer.IROptimize"
// file="RegexAnalyzerFrontEnd.IROptimize"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
@@ -37,7 +37,7 @@ using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.Text
{
public partial class RegexAnalyzer
public partial class RegexAnalyzerFrontEnd
{
internal static void ScanAndOptimizeIR(
@@ -50,7 +50,10 @@ namespace StgSharp.RegularAnalysis.Text
List<RegexIR> opt_ir = new(origin_ir.Count);
RegexIR[] opt_window = new RegexIR[8];
Span<RegexIR> opt_win_sp = opt_window;
opt_cycle:
int result;
// phase 0: common opt
phase_zero:
opt_count = 0;
int index = 0;
Span<RegexIR> origin_span = CollectionsMarshal.AsSpan(origin_ir);
@@ -62,7 +65,6 @@ namespace StgSharp.RegularAnalysis.Text
opt_win_sp.Clear();
origin_span[index..last].CopyTo(opt_win_sp);
int result;
if ((result = TryExpandPlus(opt_win_sp, opt_ir)) >= 0)
{
process_count++;
@@ -130,12 +132,14 @@ namespace StgSharp.RegularAnalysis.Text
}
(origin_ir, opt_ir) = (opt_ir, origin_ir);
opt_ir.Clear();
goto opt_cycle;
goto phase_zero;
}
/**/
// phase 1: dot star replace
(origin_ir, opt_ir) = (opt_ir, origin_ir);
opt_ir.Clear();
index = 0;
opt_count = 0;
origin_span = CollectionsMarshal.AsSpan(origin_ir);
do
{
@@ -150,8 +154,10 @@ namespace StgSharp.RegularAnalysis.Text
process_count += count + 1;
Span<RegexIR> opt_block = origin_span.Slice(index, count + 1);
opt_ir.AddRange(opt_block);
} else if (TryReplaceDotStar(opt_win_sp, opt_ir) >= 0)
} else
if (TryReplaceDotStar(opt_win_sp, opt_ir) >= 0)
{
opt_count++;
process_count++;
} else
{
@@ -161,7 +167,53 @@ namespace StgSharp.RegularAnalysis.Text
index += process_count;
} while (index < origin_ir.Count);
/**/
if (opt_count == 0)
{
optIR = opt_ir;
return;
}
// phase 2: find-1 merge and try-find-1 rotate
do
{
(origin_ir, opt_ir) = (opt_ir, origin_ir);
opt_ir.Clear();
opt_count = 0;
index = 0;
origin_span = CollectionsMarshal.AsSpan(origin_ir);
do
{
int process_count = 0;
int last = int.Min(origin_span.Length, index + 8);
opt_win_sp.Clear();
origin_span[index..last].CopyTo(opt_win_sp);
if (opt_win_sp[0] is IRegexComplex { IsFullyOptimized: true, CommandCount: > 0 } skip)
{
int count = skip.CommandCount;
process_count += count + 1;
Span<RegexIR> opt_block = origin_span.Slice(index, count + 1);
opt_ir.AddRange(opt_block);
} else if (TyrMergeFindRestTwice(opt_win_sp, opt_ir) == 0)
{
process_count += 2;
opt_count++;
} else if ((result = TyrMergeFindRestTry(opt_win_sp, opt_ir)) >= 0)
{
Span<RegexIR> opt_block = origin_span.Slice(index + 2, result);
opt_ir.AddRange(opt_block);
process_count += 2;
process_count += result;
opt_count++;
} else
{
opt_ir.Add(opt_win_sp[0]);
process_count++;
}
index += process_count;
} while (index < origin_ir.Count);
} while (opt_count > 0);
optIR = opt_ir;
}
@@ -285,6 +337,45 @@ namespace StgSharp.RegularAnalysis.Text
}
#region merge find and try-find
private static int TyrMergeFindRestTwice(
Span<RegexIR> window,
List<RegexIR> opt
)
{
if (window[0] is not RegexFindComplexIR { CommandCount: -1 } find_1 ||
window[1] is not RegexFindComplexIR find_2) {
return -1;
}
RegexFindComplexIR find_try = new(find_1.IsNearest && find_2.IsNearest, find_2.CommandCount)
{
IsFullyOptimized = true
};
opt.Add(find_try);
return 0;
}
private static int TyrMergeFindRestTry(
Span<RegexIR> window,
List<RegexIR> opt
)
{
if (window[0] is not RegexFindComplexIR { CommandCount: -1 } _find ||
window[1] is not RegexTryIR _try) {
return -1;
}
RegexFindComplexIR find_try = new(_find.IsNearest, _try.CommandCount)
{
IsFullyOptimized = true
};
opt.Add(find_try);
return find_try.CommandCount;
}
#endregion
#region expand once
private static void TryExpandComplex(
@@ -67,7 +67,7 @@ namespace StgSharp.RegularAnalysis.Text
}
public static partial class RegexAnalyzer
public static partial class RegexAnalyzerFrontEnd
{
public static TextRegexSource Analyze(
+2 -2
View File
@@ -87,12 +87,12 @@ namespace StgSharp.RegularAnalysis.Text
public bool IsFullyOptimized { get; set; }
public bool IsNearest { get; } = nearest;
public int CommandCount { get; set; } = count;
internal override RegexIRCommand Command => RegexIRCommand.Find_Complex;
private bool IsNearest { get; } = nearest;
internal override string AsCommand(
int lineNum
)
@@ -68,7 +68,6 @@ namespace StgSharp.RegularAnalysis.Text
}
} else
{
Console.WriteLine("returns empty");
return Token<RegexElementLabel>.Empty;
}
}
@@ -45,7 +45,9 @@ namespace StgSharp.RegularAnalysis.Text
public RegexTokenReader() { }
public RegexTokenReader(string source)
public RegexTokenReader(
string source
)
{
_source = source;
}
@@ -65,9 +67,11 @@ namespace StgSharp.RegularAnalysis.Text
{
string value = _source[(pos + 1)..(pos + 3)];
pos += 4;
if (uint.TryParse(value, out uint code) && Rune.TryCreate(code, out Rune result))
if (uint.TryParse(value, out uint code) &&
Rune.TryCreate(code, out Rune result))
{
return new Token<RegexElementLabel>(result.ToString(), 0, pos, RegexElementLabel.UNIT);
return new Token<RegexElementLabel>(result.ToString(), 0, pos,
RegexElementLabel.UNIT);
} else
{
throw new InvalidCastException($"Failed to convert {value} to a valid ascii code point.");
@@ -76,9 +80,11 @@ namespace StgSharp.RegularAnalysis.Text
{
string value = _source[(pos + 1)..(pos + 5)];
pos += 6;
if (uint.TryParse(value, out uint code) && Rune.TryCreate(code, out Rune result))
if (uint.TryParse(value, out uint code) &&
Rune.TryCreate(code, out Rune result))
{
return new Token<RegexElementLabel>(result.ToString(), 0, pos, RegexElementLabel.UNIT);
return new Token<RegexElementLabel>(result.ToString(), 0, pos,
RegexElementLabel.UNIT);
} else
{
throw new InvalidCastException($"Failed to convert {value} to a valid unicode code point.");
@@ -99,6 +105,10 @@ namespace StgSharp.RegularAnalysis.Text
}
}
throw new InvalidOperationException("Unclosed Unicode property escape sequence.");
} else if (_source[pos + 1] == '.')
{
position = pos + 2;
return new Token<RegexElementLabel>(".", 0, pos, RegexElementLabel.UNIT);
} else
{
position = pos + 2;
@@ -112,21 +122,24 @@ namespace StgSharp.RegularAnalysis.Text
{
int length = (i - pos - 1);
position = i + 1;
return new Token<RegexElementLabel>(_source[(pos)..(i + 1)], 0, position,
return new Token<RegexElementLabel>(_source[(pos)..(i + 1)], 0,
position,
RegexElementLabel.UNIT_SET);
}
}
throw new InvalidOperationException("Unclosed character set");
case '|':
position = pos + 1;
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.ALT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.ALT);
case '(':
// very comlex here
return ReadGroupBeginToken();
case ')':
position = pos + 1;
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.GROUP_END);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.GROUP_END);
case '{':
for (int i = pos + 1; i < _source.Length; i++)
{
@@ -141,20 +154,26 @@ namespace StgSharp.RegularAnalysis.Text
case '*' or '+':
int count = pos + 1 >= _source.Length ? 1 : (_source[pos + 1] == '?' ? 2 : 1);
position = pos + count;
return new Token<RegexElementLabel>(_source[(pos)..(pos + count)], 0, pos, RegexElementLabel.COUNT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + count)], 0, pos,
RegexElementLabel.COUNT);
case '?':
position = pos + 1;
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.COUNT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.COUNT);
case '.':
position = pos + 1;
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.UNIT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.UNIT_SET);
default:
position = pos + 1;
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.UNIT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.UNIT);
}
}
public bool TryReadToken(out Token<RegexElementLabel> t)
public bool TryReadToken(
out Token<RegexElementLabel> t
)
{
if (IsEmpty)
{