mainly theoratical work
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// file="TextRegexSourceGen.GenClass.MultiIR"
|
||||
// Project: StgSharp
|
||||
// Copyright (c) Nitload.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using StgSharp.RegularAnalysis.Abstraction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
internal partial class TextRegexSourceGen
|
||||
{
|
||||
|
||||
private static void GenerateRegion(
|
||||
ReadOnlySpan<RegexIR> region_ir,
|
||||
SourceGenContext sc,
|
||||
in SequenceEmitter<string> main_emitter,
|
||||
in List<SequenceEmitter<string>> sub_emitter_list
|
||||
)
|
||||
{
|
||||
int current_region = region_ir[0].Prefix.WorkingRegion;
|
||||
ReadOnlySpan<RegexIR> ir_sp = region_ir;
|
||||
ReadOnlySpan<RegexIR> scan_win;
|
||||
int index = 0;
|
||||
do
|
||||
{
|
||||
int result;
|
||||
int count = 0;
|
||||
scan_win = ir_sp[index..];
|
||||
if ((result = TryGenerateFindSeq(scan_win, sc, in main_emitter,
|
||||
in sub_emitter_list)) > 0)
|
||||
{
|
||||
count += result;
|
||||
} else
|
||||
if (TryGenerateMatchSeq(scan_win, main_emitter, sc) > 0)
|
||||
{
|
||||
count += 1;
|
||||
} else if (TryGenerateMatchSet(scan_win, main_emitter, sc) > 0)
|
||||
{
|
||||
count++;
|
||||
} else if (TryGenerateFindSeq(scan_win, main_emitter, sc) > 0)
|
||||
{
|
||||
count++;
|
||||
} else { }
|
||||
index += count;
|
||||
} while (index < ir_sp.Length);
|
||||
}
|
||||
|
||||
private static int TryGenerateFindSeq(
|
||||
ReadOnlySpan<RegexIR> scan_win,
|
||||
SourceGenContext sc,
|
||||
in SequenceEmitter<string> main_emitter,
|
||||
in List<SequenceEmitter<string>> sub_emitter_list
|
||||
)
|
||||
{
|
||||
if (scan_win[0] is not RegexFindSeqIR find) {
|
||||
return -1;
|
||||
}
|
||||
_ = main_emitter.AppendLine()
|
||||
.AppendLine(@$"//Find sequence:{FormatStringLiteral(find.Pattern)} at any pos")
|
||||
.AppendLine(@"do")
|
||||
.AppendLine(@"{");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StgSharp.RegularAnalysis.Text
|
||||
@@ -31,7 +34,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
{
|
||||
SequenceEmitter<string> se = new();
|
||||
List<SequenceEmitter<string>> sub_match_list = [];
|
||||
SourceGenContext ng = new();
|
||||
SourceGenContext sc = new();
|
||||
|
||||
RegexInfo info = source.Info;
|
||||
List<RegexIR> ir = source.IRs;
|
||||
@@ -41,25 +44,20 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
|
||||
SequenceEmitter<string> match_e = new();
|
||||
int index = 0;
|
||||
do
|
||||
int end = FindRrgionEnd(ir_sp, index);
|
||||
ReadOnlySpan<RegexIR> region = ir_sp[0..end];
|
||||
|
||||
while (true)
|
||||
{
|
||||
int result;
|
||||
|
||||
int count = int.Min(8, ir_sp.Length - index);
|
||||
ir_sp.Slice(index, count).CopyTo(scan_win);
|
||||
if (TryGenerateMatchSeq(scan_win, match_e, ng) > 0)
|
||||
GenerateRegion(region, sc, match_e, sub_match_list);
|
||||
if (end >= ir_sp.Length)
|
||||
{
|
||||
count += 1;
|
||||
} else if (TryGenerateMatchSet(scan_win, match_e, ng) > 0)
|
||||
{
|
||||
count++;
|
||||
} else if (TryGenerateFindSeq(scan_win, match_e, ng) > 0)
|
||||
{
|
||||
count++;
|
||||
} else { }
|
||||
index += count;
|
||||
} while (index < ir.Count);
|
||||
|
||||
break;
|
||||
}
|
||||
index = end;
|
||||
end = FindRrgionEnd(ir_sp, end);
|
||||
region = ir_sp[index..end];
|
||||
}
|
||||
|
||||
_ = se.AppendLine($@"public override MatchResult Match({ROS_char} text)")//
|
||||
.AppendLine(@"{");
|
||||
@@ -76,7 +74,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
.AppendLine($@"int {offset} = 0;")
|
||||
.AppendLine();
|
||||
|
||||
_ = ng.GenVarDefine(se);
|
||||
_ = sc.GenVarDefine(se);
|
||||
|
||||
_ = se.Append(match_e);
|
||||
|
||||
@@ -91,15 +89,25 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
return se;
|
||||
}
|
||||
|
||||
private static string FormatStringLiteral(
|
||||
string str
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int FindRrgionEnd(
|
||||
ReadOnlySpan<RegexIR> ir_sp,
|
||||
int current
|
||||
)
|
||||
{
|
||||
return SyntaxFactory.Literal(str).Text;
|
||||
int cur_depth = ir_sp[current].Prefix.WorkingRegion;
|
||||
int end = ir_sp.Length;
|
||||
for (; end > 0; end--)
|
||||
{
|
||||
if (ir_sp[end].Prefix.WorkingRegion == cur_depth) {
|
||||
return end;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static string FormatStringLiteral(
|
||||
char str
|
||||
string str
|
||||
)
|
||||
{
|
||||
return SyntaxFactory.Literal(str).Text;
|
||||
@@ -108,7 +116,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
#region sub generator
|
||||
|
||||
private static int TryGenerateFindSeq(
|
||||
Span<RegexIR> scan_win,
|
||||
ReadOnlySpan<RegexIR> scan_win,
|
||||
SequenceEmitter<string> se,
|
||||
SourceGenContext ng
|
||||
)
|
||||
@@ -129,7 +137,7 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
}
|
||||
|
||||
private static int TryGenerateMatchSeq(
|
||||
Span<RegexIR> scan_win,
|
||||
ReadOnlySpan<RegexIR> scan_win,
|
||||
SequenceEmitter<string> se,
|
||||
SourceGenContext ng
|
||||
)
|
||||
@@ -148,114 +156,8 @@ namespace StgSharp.RegularAnalysis.Text
|
||||
return length;
|
||||
}
|
||||
|
||||
private static int TryGenerateFindSet(
|
||||
Span<RegexIR> scan_win,
|
||||
SequenceEmitter<string> se,
|
||||
SourceGenContext ng
|
||||
)
|
||||
{
|
||||
if (scan_win[0] is not RegexFindSetIR seq) {
|
||||
return -1;
|
||||
}
|
||||
string pattern = seq.Charset;
|
||||
|
||||
RegexCharSet[] set_pattern = FigureCharSetType(pattern, out bool accept);
|
||||
|
||||
bool first = seq.IsFirst;
|
||||
|
||||
string remain = ng.CurRemain;
|
||||
string offset = ng.FindResult;
|
||||
_ = se.AppendLine($@"// match charset of {pattern}")
|
||||
.AppendLine($@"{remain} = {orig_text}[{current_ptr}..];")
|
||||
.AppendLine();
|
||||
|
||||
_ = se.AppendLine("if(");
|
||||
RegexCharSet p = set_pattern[0];
|
||||
string _case = accept ? GenerateAcceptCase(p) : GenerateDenyCase(p);
|
||||
_ = se.AppendLine($@"if ({_case}||");
|
||||
|
||||
for (int i = 1; i < set_pattern.Length - 1; i++)
|
||||
{
|
||||
p = set_pattern[i];
|
||||
_case = accept ? GenerateAcceptCase(p) : GenerateDenyCase(p);
|
||||
if (string.IsNullOrEmpty(_case))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_ = se.AppendLine($@" {_case} ||");
|
||||
}
|
||||
|
||||
p = set_pattern[^1];
|
||||
_case = accept ? GenerateAcceptCase(p) : GenerateDenyCase(p);
|
||||
_ = se.AppendLine($@"{_case})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{current_ptr} += 1;")
|
||||
.AppendLine("}");
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
string GenerateAcceptCase(
|
||||
RegexCharSet c
|
||||
)
|
||||
{
|
||||
string caller;
|
||||
switch (c.Type)
|
||||
{
|
||||
// Handle single character
|
||||
case CharSetType.Single:
|
||||
string literal = FormatStringLiteral(c.Value);
|
||||
caller = first ? "IndexOfAny" : "LastIndexOfAny";
|
||||
return $@"({offset} = {remain}.{caller}(""{literal}"") != -1)";
|
||||
|
||||
// Handle range of characters
|
||||
case CharSetType.Range:
|
||||
caller = first ? "IndexOfAnyInRange" : "LastIndexOfAnyInRange";
|
||||
return $@"({offset} = {remain}.{caller}('{FormatStringLiteral(c.Value[0])}', '{FormatStringLiteral(c.Value[1])}') != -1)";
|
||||
|
||||
// Handle set of characters
|
||||
case CharSetType.Set:
|
||||
switch (c.Value)
|
||||
{
|
||||
case "s":
|
||||
caller = first ? "IndexOfAnyWhiteSpace" : "LastIndexOfAnyWhiteSpace";
|
||||
return $@"({offset} = {remain}.{caller}() != -1)";
|
||||
case "w":
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case CharSetType.None:
|
||||
return string.Empty;
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
string GenerateDenyCase(
|
||||
RegexCharSet c
|
||||
)
|
||||
{
|
||||
switch (c.Type)
|
||||
{
|
||||
// Handle single character
|
||||
case CharSetType.Single:
|
||||
|
||||
// Handle range of characters
|
||||
case CharSetType.Range:
|
||||
|
||||
// Handle set of characters
|
||||
case CharSetType.Set:
|
||||
case CharSetType.None:
|
||||
return string.Empty;
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int TryGenerateMatchSet(
|
||||
Span<RegexIR> scan_win,
|
||||
ReadOnlySpan<RegexIR> scan_win,
|
||||
SequenceEmitter<string> se,
|
||||
SourceGenContext ng
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user