do some source gen work
This commit is contained in:
@@ -82,7 +82,7 @@
|
|||||||
<ManagedBuildDir>$(SolutionRoot)bin\$(BuildRid)\</ManagedBuildDir>
|
<ManagedBuildDir>$(SolutionRoot)bin\$(BuildRid)\</ManagedBuildDir>
|
||||||
|
|
||||||
<!-- CMake native 最终二进制输出目录 -->
|
<!-- CMake native 最终二进制输出目录 -->
|
||||||
<NativeBuildDir>$(SolutionRoot)bin\$(_OsTag)_$(_ArchTag)\</NativeBuildDir>
|
<NativeBuildDir>$(SolutionRoot)bin\$(BuildRid)\</NativeBuildDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- ════════════════════════════════════════════════════════ -->
|
<!-- ════════════════════════════════════════════════════════ -->
|
||||||
|
|||||||
+14
-14
@@ -66,32 +66,32 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- 扫描 bin/ 下所有 RID 子目录中的 native 文件 -->
|
<!-- 扫描 bin/ 下所有 RID 子目录中的 native 文件 -->
|
||||||
<_PackNative Include="$(SolutionRoot)bin\win_x64\$(NativeLibName).dll"
|
<_PackNative Include="$(SolutionRoot)bin\win-x64\$(NativeLibName).dll"
|
||||||
Condition="Exists('$(SolutionRoot)bin\win_x64\$(NativeLibName).dll')"
|
Condition="Exists('$(SolutionRoot)bin\win-x64\$(NativeLibName).dll')"
|
||||||
PackagePath="runtimes\win-x64\native" Pack="true" />
|
PackagePath="runtimes\win-x64\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\win_arm64\$(NativeLibName).dll"
|
<_PackNative Include="$(SolutionRoot)bin\win-arm64\$(NativeLibName).dll"
|
||||||
Condition="Exists('$(SolutionRoot)bin\win_arm64\$(NativeLibName).dll')"
|
Condition="Exists('$(SolutionRoot)bin\win-arm64\$(NativeLibName).dll')"
|
||||||
PackagePath="runtimes\win-arm64\native" Pack="true" />
|
PackagePath="runtimes\win-arm64\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\linux_x64\lib$(NativeLibName).so"
|
<_PackNative Include="$(SolutionRoot)bin\linux-x64\lib$(NativeLibName).so"
|
||||||
Condition="Exists('$(SolutionRoot)bin\linux_x64\lib$(NativeLibName).so')"
|
Condition="Exists('$(SolutionRoot)bin\linux-x64\lib$(NativeLibName).so')"
|
||||||
PackagePath="runtimes\linux-x64\native" Pack="true" />
|
PackagePath="runtimes\linux-x64\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\linux_arm64\lib$(NativeLibName).so"
|
<_PackNative Include="$(SolutionRoot)bin\linux-arm64\lib$(NativeLibName).so"
|
||||||
Condition="Exists('$(SolutionRoot)bin\linux_arm64\lib$(NativeLibName).so')"
|
Condition="Exists('$(SolutionRoot)bin\linux-arm64\lib$(NativeLibName).so')"
|
||||||
PackagePath="runtimes\linux-arm64\native" Pack="true" />
|
PackagePath="runtimes\linux-arm64\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\linux_ppc64le\lib$(NativeLibName).so"
|
<_PackNative Include="$(SolutionRoot)bin\linux-ppc64le\lib$(NativeLibName).so"
|
||||||
Condition="Exists('$(SolutionRoot)bin\linux_ppc64le\lib$(NativeLibName).so')"
|
Condition="Exists('$(SolutionRoot)bin\linux-ppc64le\lib$(NativeLibName).so')"
|
||||||
PackagePath="runtimes\linux-ppc64le\native" Pack="true" />
|
PackagePath="runtimes\linux-ppc64le\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\osx_x64\lib$(NativeLibName).dylib"
|
<_PackNative Include="$(SolutionRoot)bin\osx-x64\lib$(NativeLibName).dylib"
|
||||||
Condition="Exists('$(SolutionRoot)bin\osx_x64\lib$(NativeLibName).dylib')"
|
Condition="Exists('$(SolutionRoot)bin\osx-x64\lib$(NativeLibName).dylib')"
|
||||||
PackagePath="runtimes\osx-x64\native" Pack="true" />
|
PackagePath="runtimes\osx-x64\native" Pack="true" />
|
||||||
|
|
||||||
<_PackNative Include="$(SolutionRoot)bin\osx_arm64\lib$(NativeLibName).dylib"
|
<_PackNative Include="$(SolutionRoot)bin\osx-arm64\lib$(NativeLibName).dylib"
|
||||||
Condition="Exists('$(SolutionRoot)bin\osx_arm64\lib$(NativeLibName).dylib')"
|
Condition="Exists('$(SolutionRoot)bin\osx-arm64\lib$(NativeLibName).dylib')"
|
||||||
PackagePath="runtimes\osx-arm64\native" Pack="true" />
|
PackagePath="runtimes\osx-arm64\native" Pack="true" />
|
||||||
|
|
||||||
<None Include="@(_PackNative)" />
|
<None Include="@(_PackNative)" />
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ else()
|
|||||||
set(STGSHARP_ARCH_TAG ${SN_RESOLVED_ARCH_NAME})
|
set(STGSHARP_ARCH_TAG ${SN_RESOLVED_ARCH_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(STGSHARP_BUILD_OUTPUT_DIR ${STGSHARP_SOLUTION_ROOT}/bin/${STGSHARP_OS_TAG}_${STGSHARP_ARCH_TAG})
|
set(STGSHARP_BUILD_OUTPUT_DIR ${STGSHARP_SOLUTION_ROOT}/bin/${STGSHARP_OS_TAG}-${STGSHARP_ARCH_TAG})
|
||||||
# Compile-time intermediates (native PDB / .obj side files) live inside the CMake
|
# Compile-time intermediates (native PDB / .obj side files) live inside the CMake
|
||||||
# build tree (cmake_build/<preset>) so they get cleaned up with it.
|
# build tree (cmake_build/<preset>) so they get cleaned up with it.
|
||||||
set(STGSHARP_OBJECT_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/obj/${PROJECT_NAME})
|
set(STGSHARP_OBJECT_ROOT_DIR ${CMAKE_CURRENT_BINARY_DIR}/obj/${PROJECT_NAME})
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
ref RegexInfo info
|
ref RegexInfo info
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
List<RegexIR> list = GenerateIRRecursion(tree.Root, 0, out int length).ToList();
|
List<RegexIR> list = GenerateIRRecursion(tree.Root, 0, [], out int length).ToList();
|
||||||
info.MinPredictLength = length;
|
info.MinPredictLength = length;
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -41,15 +41,17 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
int max,
|
int max,
|
||||||
bool isGreedy,
|
bool isGreedy,
|
||||||
RegexAstNode right,
|
RegexAstNode right,
|
||||||
|
HashSet<string> group_names,
|
||||||
out int minLength
|
out int minLength
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool is_operator = !RegexAstNode.IsNullOrEmpty(right) &&
|
bool is_operator = !RegexAstNode.IsNullOrEmpty(right) &&
|
||||||
(right.Source.Flag & RegexElementLabel.OPERATOR) != 0;
|
(right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0;
|
||||||
|
|
||||||
if (is_operator) // seq to be count is complex
|
if (is_operator) // seq to be count is complex
|
||||||
{
|
{
|
||||||
RegexIRGenerator right_ir = GenerateIRRecursion(right, curDepth + 1, out minLength);
|
RegexIRGenerator right_ir = GenerateIRRecursion(right, curDepth + 1, group_names,
|
||||||
|
out minLength);
|
||||||
_ = ir.EmitCountComplex(min, max, isGreedy, right_ir.Count);
|
_ = ir.EmitCountComplex(min, max, isGreedy, right_ir.Count);
|
||||||
_ = ir.EmitIRStream(right_ir);
|
_ = ir.EmitIRStream(right_ir);
|
||||||
} else
|
} else
|
||||||
@@ -78,6 +80,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
private static RegexIRGenerator GenerateIRRecursion(
|
private static RegexIRGenerator GenerateIRRecursion(
|
||||||
RegexAstNode node,
|
RegexAstNode node,
|
||||||
int depth,
|
int depth,
|
||||||
|
HashSet<string> group_names,
|
||||||
out int minLength
|
out int minLength
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -94,20 +97,28 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
|
|
||||||
Token<RegexElementLabel> token = node.Source;
|
Token<RegexElementLabel> token = node.Source;
|
||||||
|
|
||||||
|
HashSet<string> gn = group_names ?? [];
|
||||||
|
|
||||||
switch (node.Source.Flag)
|
switch (node.Source.Flag)
|
||||||
{
|
{
|
||||||
case RegexElementLabel.GROUP_BEGIN:
|
case RegexElementLabel.GROUP_BEGIN:
|
||||||
string group_source = token.Value;
|
string group_source = token.Value;
|
||||||
|
|
||||||
// process group type
|
// process group type
|
||||||
bool is_group = group_source.Length == 1; // simple group: (pattern)
|
bool has_name = group_source.StartsWith(@"(?<", StringComparison.Ordinal); // simple group: (pattern)
|
||||||
string group_name =
|
string group_name = has_name ?
|
||||||
group_source.StartsWith(@"(?<", StringComparison.Ordinal) ?
|
group_source[3..^1] : /* named group (?<name>) */
|
||||||
group_source[3..^1] : /* named group (?<name>) */
|
string.Empty; /* unnamed group (?:) */
|
||||||
string.Empty; /* unnamed group (?:) */
|
|
||||||
|
if (has_name)
|
||||||
|
{
|
||||||
|
if (!gn.Add(group_name)) {
|
||||||
|
throw new InvalidOperationException($"Duplicate group name: {group_name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RegexIRGenerator groupIR = new();
|
RegexIRGenerator groupIR = new();
|
||||||
rightIR = GenerateIRRecursion(right, curDepth + 1, out minLength);
|
rightIR = GenerateIRRecursion(right, curDepth + 1, gn, out minLength);
|
||||||
_ = groupIR.EmitTry(rightIR.Count)
|
_ = groupIR.EmitTry(rightIR.Count)
|
||||||
.EmitIRStream(rightIR)
|
.EmitIRStream(rightIR)
|
||||||
.EmitCondition(2, 1)
|
.EmitCondition(2, 1)
|
||||||
@@ -123,15 +134,15 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
int length_once;
|
int length_once;
|
||||||
if (count_source_span[0] == '*') // infinite count
|
if (count_source_span[0] == '*') // infinite count
|
||||||
{
|
{
|
||||||
EmitCount(curDepth, count_ir, 0, -1, isGreedy, seq, out _);
|
EmitCount(curDepth, count_ir, 0, -1, isGreedy, seq, gn, out _);
|
||||||
minLength = 0;
|
minLength = 0;
|
||||||
} else if (count_source_span[0] == '+') // at least one
|
} else if (count_source_span[0] == '+') // at least one
|
||||||
{
|
{
|
||||||
EmitCount(curDepth, count_ir, 1, -1, isGreedy, seq, out length_once);
|
EmitCount(curDepth, count_ir, 1, -1, isGreedy, seq, gn, out length_once);
|
||||||
minLength = length_once;
|
minLength = length_once;
|
||||||
} else if (count_source_span[0] == '?') // zero or one
|
} else if (count_source_span[0] == '?') // zero or one
|
||||||
{
|
{
|
||||||
EmitCount(curDepth, count_ir, 0, 1, isGreedy, seq, out _);
|
EmitCount(curDepth, count_ir, 0, 1, isGreedy, seq, gn, out _);
|
||||||
minLength = 0;
|
minLength = 0;
|
||||||
} else if (count_source_span[0] == '{') // zero or one, non-greedy
|
} else if (count_source_span[0] == '{') // zero or one, non-greedy
|
||||||
{
|
{
|
||||||
@@ -140,7 +151,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
{
|
{
|
||||||
if (int.TryParse(count_source[1..(isGreedy ? ^2 : ^1)], out int count))
|
if (int.TryParse(count_source[1..(isGreedy ? ^2 : ^1)], out int count))
|
||||||
{
|
{
|
||||||
EmitCount(curDepth, count_ir, count, count, isGreedy, seq,
|
EmitCount(curDepth, count_ir, count, count, isGreedy, seq, gn,
|
||||||
out length_once);
|
out length_once);
|
||||||
minLength = length_once * count;
|
minLength = length_once * count;
|
||||||
} else
|
} else
|
||||||
@@ -152,7 +163,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
if (int.TryParse(count_source[1..comma_pos], out int min) &&
|
if (int.TryParse(count_source[1..comma_pos], out int min) &&
|
||||||
int.TryParse(count_source[(comma_pos + 1)..(isGreedy ? ^1 : ^2)], out int max))
|
int.TryParse(count_source[(comma_pos + 1)..(isGreedy ? ^1 : ^2)], out int max))
|
||||||
{
|
{
|
||||||
EmitCount(curDepth, count_ir, min, max, isGreedy, seq,
|
EmitCount(curDepth, count_ir, min, max, isGreedy, seq, gn,
|
||||||
out length_once);
|
out length_once);
|
||||||
minLength = length_once * min;
|
minLength = length_once * min;
|
||||||
} else
|
} else
|
||||||
@@ -195,7 +206,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
}
|
}
|
||||||
} else if ((left.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
|
} else if ((left.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
|
||||||
{
|
{
|
||||||
leftIR = GenerateIRRecursion(left, curDepth + 1, out left_length);
|
leftIR = GenerateIRRecursion(left, curDepth + 1, gn, out left_length);
|
||||||
_ = concat.EmitIRStream(leftIR);
|
_ = concat.EmitIRStream(leftIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +236,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
}
|
}
|
||||||
} else if ((right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
|
} else if ((right.Source.Flag & RegexElementLabel.VAST_OPERATOR) != 0)
|
||||||
{
|
{
|
||||||
rightIR = GenerateIRRecursion(right, curDepth + 1, out right_length);
|
rightIR = GenerateIRRecursion(right, curDepth + 1, gn, out right_length);
|
||||||
_ = concat.EmitIRStream(rightIR);
|
_ = concat.EmitIRStream(rightIR);
|
||||||
}
|
}
|
||||||
minLength = left_length + right_length;
|
minLength = left_length + right_length;
|
||||||
@@ -238,7 +249,8 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
int min_case_length = int.MaxValue;
|
int min_case_length = int.MaxValue;
|
||||||
while (!RegexAstNode.IsNullOrEmpty(cur_node))
|
while (!RegexAstNode.IsNullOrEmpty(cur_node))
|
||||||
{
|
{
|
||||||
RegexIRGenerator _case = GenerateIRRecursion(cur_node, curDepth + 1, out int case_length);
|
RegexIRGenerator _case = GenerateIRRecursion(cur_node, curDepth + 1, gn,
|
||||||
|
out int case_length);
|
||||||
min_case_length = int.Min(case_length, min_case_length);
|
min_case_length = int.Min(case_length, min_case_length);
|
||||||
casesIRList.Add(_case);
|
casesIRList.Add(_case);
|
||||||
ir_count += _case.Count;
|
ir_count += _case.Count;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
[Flags]
|
[Flags]
|
||||||
public enum RegexElementLabel
|
public enum RegexElementLabel
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CA1707
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
UNIT = 1,
|
UNIT = 1,
|
||||||
UNIT_SET = 2,
|
UNIT_SET = 2,
|
||||||
@@ -33,5 +33,6 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
ATOM_BEGIN = SEQUENCE | GROUP_BEGIN ,
|
ATOM_BEGIN = SEQUENCE | GROUP_BEGIN ,
|
||||||
ATOM_END = SEQUENCE | GROUP_END | COUNT,
|
ATOM_END = SEQUENCE | GROUP_END | COUNT,
|
||||||
|
|
||||||
|
#pragma warning restore CA1707
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,10 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
}
|
}
|
||||||
if (Source.TryReadToken(out Token<RegexElementLabel> orig))
|
if (Source.TryReadToken(out Token<RegexElementLabel> orig))
|
||||||
{
|
{
|
||||||
if (((int)(orig.Flag & RegexElementLabel.ATOM_BEGIN) != 0) && ((int)_prev != 0))
|
if (((orig.Flag & RegexElementLabel.ATOM_BEGIN) != 0) && (_prev != 0))
|
||||||
{
|
{
|
||||||
Token<RegexElementLabel> ret = new Token<RegexElementLabel>(string.Empty,
|
Token<RegexElementLabel> ret = new(string.Empty, orig.Line, orig.Column,
|
||||||
orig.Line,
|
RegexElementLabel.CONCAT);
|
||||||
orig.Column,
|
|
||||||
RegexElementLabel.CONCAT);
|
|
||||||
_buffer.Enqueue(orig);
|
_buffer.Enqueue(orig);
|
||||||
_prev = orig.Flag & RegexElementLabel.ATOM_END;
|
_prev = orig.Flag & RegexElementLabel.ATOM_END;
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
// -----------------------------------------------------------------------------
|
|
||||||
// file="RegexTokenUtil"
|
|
||||||
// Project: StgSharp
|
|
||||||
// Copyright (c) Nitload.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
using StgSharp.RegularAnalysis.Abstraction;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace StgSharp.RegularAnalysis.Text
|
|
||||||
{
|
|
||||||
internal static class RegexTokenUtil
|
|
||||||
{
|
|
||||||
|
|
||||||
public static bool IsAccurateChar(
|
|
||||||
this Token<RegexElementLabel> token
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return ((token.Flag & RegexElementLabel.UNIT) != 0 && token.Value.Length == 1) ||
|
|
||||||
(token.Flag & RegexElementLabel.UNIT_SPAN) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,17 +14,12 @@ using System.Threading.Tasks;
|
|||||||
namespace StgSharp.RegularAnalysis.Text
|
namespace StgSharp.RegularAnalysis.Text
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||||
public sealed class TextRegexAttribute : Attribute
|
public sealed class TextRegexAttribute(
|
||||||
|
string pattern
|
||||||
|
) : Attribute
|
||||||
{
|
{
|
||||||
|
|
||||||
public TextRegexAttribute(
|
public string Pattern { get; } = pattern;
|
||||||
string pattern
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Pattern = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Pattern { get; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
using StgSharp.RegularAnalysis.Abstraction;
|
using StgSharp.RegularAnalysis.Abstraction;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -18,12 +19,16 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
internal partial class TextRegexSourceGen
|
internal partial class TextRegexSourceGen
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private const string current_ptr = "current_ptr";
|
||||||
|
private const string orig_text = "text";
|
||||||
|
|
||||||
internal static SequenceEmitter<string> GenerateSource(
|
internal static SequenceEmitter<string> GenerateSource(
|
||||||
TextRegexSource source
|
TextRegexSource source
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SequenceEmitter<string> se = new();
|
SequenceEmitter<string> se = new();
|
||||||
List<SequenceEmitter<string>> sub_match_list = [];
|
List<SequenceEmitter<string>> sub_match_list = [];
|
||||||
|
VarNameGenerator ng = new();
|
||||||
|
|
||||||
RegexInfo info = source.Info;
|
RegexInfo info = source.Info;
|
||||||
List<RegexIR> ir = source.IRs;
|
List<RegexIR> ir = source.IRs;
|
||||||
@@ -31,8 +36,6 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
RegexIR[] window = new RegexIR[8];
|
RegexIR[] window = new RegexIR[8];
|
||||||
Span<RegexIR> scan_win = window;
|
Span<RegexIR> scan_win = window;
|
||||||
|
|
||||||
const string current_ptr = "current_ptr";
|
|
||||||
|
|
||||||
_ = se.AppendLine($@"public override MatchResult Match({ROS_char} text)")//
|
_ = se.AppendLine($@"public override MatchResult Match({ROS_char} text)")//
|
||||||
.AppendLine(@"{");
|
.AppendLine(@"{");
|
||||||
|
|
||||||
@@ -49,9 +52,18 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
int count = int.Min(8, ir_sp.Length - index);
|
int count = int.Min(8, ir_sp.Length - index);
|
||||||
ir_sp.Slice(index, count).CopyTo(scan_win);
|
ir_sp.Slice(index, count).CopyTo(scan_win);
|
||||||
if (TryGenerateMatch(scan_win, se) > 0) { }
|
if (TryGenerateMatchSeq(scan_win, se, ng) > 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
} else if (TryGenerateMatchSet(scan_win, se, ng) > 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
} else { }
|
||||||
|
index += count;
|
||||||
} while (index < ir.Count);
|
} while (index < ir.Count);
|
||||||
|
|
||||||
foreach (SequenceEmitter<string> _sub in sub_match_list)
|
foreach (SequenceEmitter<string> _sub in sub_match_list)
|
||||||
@@ -63,27 +75,203 @@ namespace StgSharp.RegularAnalysis.Text
|
|||||||
_ = se.Append(@"}");
|
_ = se.Append(@"}");
|
||||||
|
|
||||||
return se;
|
return se;
|
||||||
/**/
|
|
||||||
int TryGenerateMatch(
|
|
||||||
Span<RegexIR> scan_win,
|
|
||||||
SequenceEmitter<string> sb
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (scan_win[0] is not RegexMatchSeqIR seq) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
string pattern = seq.Pattern;
|
|
||||||
int length = pattern.Length;
|
|
||||||
_ = sb.AppendLine()
|
|
||||||
.AppendLine($@"if(text[{current_ptr}..({current_ptr} + {length})] == {pattern})")
|
|
||||||
.AppendLine($@"{{")
|
|
||||||
.AppendLine($@"{current_ptr} += {length};")
|
|
||||||
.AppendLine($@"}}");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/**/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region var naming
|
||||||
|
|
||||||
|
private class VarNameGenerator
|
||||||
|
{
|
||||||
|
|
||||||
|
private int char_counter;
|
||||||
|
|
||||||
|
public string GenerateCharName()
|
||||||
|
{
|
||||||
|
string name = $"__char_{char_counter}";
|
||||||
|
char_counter++;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region sub generator
|
||||||
|
|
||||||
|
private static int TryGenerateMatchSeq(
|
||||||
|
Span<RegexIR> scan_win,
|
||||||
|
SequenceEmitter<string> se,
|
||||||
|
VarNameGenerator ng
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (scan_win[0] is not RegexMatchSeqIR seq) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
string pattern = seq.Pattern;
|
||||||
|
int length = pattern.Length;
|
||||||
|
_ = se.AppendLine()
|
||||||
|
.AppendLine($@"if(text[{current_ptr}..({current_ptr} + {length})] == {pattern})")
|
||||||
|
.AppendLine($@"{{")
|
||||||
|
.AppendLine($@"{current_ptr} += {length};")
|
||||||
|
.AppendLine($@"}}");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int TryGenerateMatchSet(
|
||||||
|
Span<RegexIR> scan_win,
|
||||||
|
SequenceEmitter<string> se,
|
||||||
|
VarNameGenerator ng
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (scan_win[0] is not RegexMatchSeqIR seq) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
string pattern = seq.Pattern;
|
||||||
|
RegexCharSet[] set_pattern = FigureCharSetType(pattern);
|
||||||
|
|
||||||
|
string var_char = ng.GenerateCharName();
|
||||||
|
_ = se.AppendLine($@"// match charset of {pattern}")
|
||||||
|
.AppendLine($@"char {var_char} = {orig_text}[{current_ptr}];")
|
||||||
|
.AppendLine();
|
||||||
|
|
||||||
|
bool accept = set_pattern[0].Accept;
|
||||||
|
|
||||||
|
_ = se.AppendLine("if(");
|
||||||
|
RegexCharSet p = set_pattern[0];
|
||||||
|
string _case = GenerateCase(p);
|
||||||
|
string _case_begin = accept ? string.Empty : "!(";
|
||||||
|
_ = se.AppendLine($@"if ({_case_begin}{_case}||");
|
||||||
|
|
||||||
|
for (int i = 1; i < set_pattern.Length - 1; i++)
|
||||||
|
{
|
||||||
|
p = set_pattern[i];
|
||||||
|
_case = GenerateCase(p);
|
||||||
|
if (string.IsNullOrEmpty(_case))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ = se.AppendLine($@" {_case} ||");
|
||||||
|
}
|
||||||
|
|
||||||
|
p = set_pattern[^1];
|
||||||
|
_case = GenerateCase(p);
|
||||||
|
string _case_end = accept ? string.Empty : ")";
|
||||||
|
_ = se.AppendLine($@"{_case}{_case_end})")
|
||||||
|
.AppendLine("{")
|
||||||
|
.AppendLine($@"{current_ptr} += 1;")
|
||||||
|
.AppendLine("}");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
string GenerateCase(
|
||||||
|
RegexCharSet c
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return c.Type switch
|
||||||
|
{
|
||||||
|
// Handle single character
|
||||||
|
CharSetType.Single => $@"{var_char} == '{c.Value}'",
|
||||||
|
|
||||||
|
// Handle range of characters
|
||||||
|
CharSetType.Range => $@"({var_char} >= '{c.Value[0]}' && {var_char} <= '{c.Value[1]}')",
|
||||||
|
|
||||||
|
// Handle set of characters
|
||||||
|
CharSetType.Set => c.Value switch
|
||||||
|
{
|
||||||
|
"s" => $@"char.IsWhiteSpace({var_char})",
|
||||||
|
"w" => $@"char.IsLetterOrDigit({var_char}) || {var_char} == '_'",
|
||||||
|
"d" => $@"char.IsDigit({var_char})",
|
||||||
|
_ => throw new InvalidCastException(),
|
||||||
|
},
|
||||||
|
CharSetType.None => string.Empty,
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region charset config
|
||||||
|
|
||||||
|
internal enum CharSetType
|
||||||
|
{
|
||||||
|
|
||||||
|
None,
|
||||||
|
Single,
|
||||||
|
Range,
|
||||||
|
Set
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal record struct RegexCharSet(
|
||||||
|
string Value,
|
||||||
|
CharSetType Type,
|
||||||
|
bool Accept
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
public override readonly string ToString()
|
||||||
|
{
|
||||||
|
return $"{{value:{Value}, type:{Type}, accept:{Accept}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegexCharSet[] FigureCharSetType(
|
||||||
|
ReadOnlySpan<char> source
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// range or single
|
||||||
|
bool accept;
|
||||||
|
if (source[0] == '[')
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
accept = source[1] != '^';
|
||||||
|
idx = accept ? 1 : 2;
|
||||||
|
ReadOnlySpan<char> seq = source.Slice(idx, source.Length - idx - 1);
|
||||||
|
if (seq.IndexOf('-') == -1)
|
||||||
|
{
|
||||||
|
return [new RegexCharSet(seq.ToString(), CharSetType.Single, accept)];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
seq = seq[(pos + 2)..];
|
||||||
|
}
|
||||||
|
return [.. list];
|
||||||
|
}
|
||||||
|
} else if (source[0] == '\\')
|
||||||
|
{
|
||||||
|
// set
|
||||||
|
accept = char.IsAsciiLetterUpper(source[0]);
|
||||||
|
return char.ToLower(source[0], CultureInfo.InvariantCulture)
|
||||||
|
switch
|
||||||
|
{
|
||||||
|
's' => [new("s", CharSetType.Set, accept)],
|
||||||
|
'w' => [new("w", CharSetType.Set, accept)],
|
||||||
|
'd' => [new("d", CharSetType.Set, accept)],
|
||||||
|
_ => throw new NotSupportedException()
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// unknown, throw
|
||||||
|
throw new InvalidCastException($"Unknown char set: {source}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ namespace StgSharp
|
|||||||
{
|
{
|
||||||
|
|
||||||
private static string[] regexSource = [
|
private static string[] regexSource = [
|
||||||
@"(a|b)(c|d)",
|
@"(?<name>123)(?<name>123)",
|
||||||
/**/
|
/*
|
||||||
@"http|https|ftp|ftps",
|
@"http|https|ftp|ftps",
|
||||||
@"abc[0-9]x|abc[0-9]y|abd[0-9]x|abd[0-9]y|xyz",
|
@"abc[0-9]x|abc[0-9]y|abd[0-9]x|abd[0-9]y|xyz",
|
||||||
@"get_name|get_value|get_type|set_name|set_value|set_type",
|
@"get_name|get_value|get_type|set_name|set_value|set_type",
|
||||||
@@ -52,11 +52,16 @@ namespace StgSharp
|
|||||||
Console.WriteLine(ir[i].AsCommand(i));
|
Console.WriteLine(ir[i].AsCommand(i));
|
||||||
}
|
}
|
||||||
/**/
|
/**/
|
||||||
|
/**/
|
||||||
Console.WriteLine("-----Optimized once-----");
|
Console.WriteLine("-----Optimized once-----");
|
||||||
List<RegexIR> opt_ir = interpreterSource.IRs;
|
List<RegexIR> opt_ir = interpreterSource.IRs;
|
||||||
for (int i = 0; i < opt_ir.Count; i++) {
|
if (opt_ir is not null)
|
||||||
Console.WriteLine(opt_ir[i].AsCommand(i));
|
{
|
||||||
|
for (int i = 0; i < opt_ir.Count; i++) {
|
||||||
|
Console.WriteLine(opt_ir[i].AsCommand(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/**/
|
||||||
Console.WriteLine(interpreterSource.AnalyseException?.ToString() ?? "No error");
|
Console.WriteLine(interpreterSource.AnalyseException?.ToString() ?? "No error");
|
||||||
RegexInfo info = interpreterSource.Info;
|
RegexInfo info = interpreterSource.Info;
|
||||||
Console.WriteLine("-----Regex Info-----");
|
Console.WriteLine("-----Regex Info-----");
|
||||||
|
|||||||
Reference in New Issue
Block a user