add more generate method of ALT node, add improve advise for gl source gen

This commit is contained in:
Youmu Liu
2026-08-24 18:12:36 +08:00
parent f0b6a4038e
commit 708a915549
3 changed files with 736 additions and 17 deletions
+12 -12
View File
@@ -84,21 +84,21 @@ namespace StgSharp.RegularAnalysis.Text
/// <see langword="false" />.
/// </returns>
/// <remarks>
/// <para> /// This method operates on a single <see cref="char" />, and therefore /// on
/// a single UTF-16 code unit rather than on a complete Unicode scalar /// value.
/// ///</para> <para> /// Characters in the Unicode Basic Multilingual Plane are
/// classified /// normally. A supplementary-plane character is represented by a ///
/// surrogate pair and is therefore presented to this method as two /// separate surrogate
/// code units. Neither surrogate is independently /// treated as a word character. This
/// follows the char-based behavior of /// the corresponding .NET Regex helper. ///</para>
/// <para> /// For ASCII input, the Unicode-category lookup is avoided. In ASCII, /// the
/// accepted set is exactly: /// <c> [A-Za-z0-9_] </c>. ///</para> <para> /// This method
/// <para>/// This method operates on a single <see cref="char" />, and therefore /// on a
/// single UTF-16 code unit rather than on a complete Unicode scalar /// value. ///
/// </para> <para>/// Characters in the Unicode Basic Multilingual Plane are classified
/// /// normally. A supplementary-plane character is represented by a /// surrogate pair
/// and is therefore presented to this method as two /// separate surrogate code units.
/// Neither surrogate is independently /// treated as a word character. This follows the
/// char-based behavior of /// the corresponding .NET Regex helper. /// </para> <para>///
/// For ASCII input, the Unicode-category lookup is avoided. In ASCII, /// the accepted
/// set is exactly: /// <c> [A-Za-z0-9_] </c>. /// </para> <para>/// This method
/// implements ordinary .NET <c> \w </c> semantics. It does /// not implement the ASCII-
/// oriented behavior enabled by /// <c> RegexOptions.ECMAScript </c>. ///</para>
/// oriented behavior enabled by /// <c> RegexOptions.ECMAScript </c>. /// </para>
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static bool IsCharWord(
char value
protected internal static bool IsCharWord(
char value
)
{
/*
@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp;
using StgSharp.RegularAnalysis.Abstraction;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -82,6 +83,36 @@ namespace StgSharp.RegularAnalysis.Text
return SyntaxFactory.Literal(value).Text;
}
private static string GenerateCharSetExpression(
RegexCharSet set
)
{
string remainSpan = SourceGenContext._remain_span;
string accept = set.Accept ? string.Empty : "!";
switch (set.Type)
{
case RegexCharSetType.Single:
return $"{accept}({FormatStringLiteral(set.Value)}.{nameof(MemoryExtensions.Contains)}({remainSpan}[0]))";
case RegexCharSetType.Range:
return $"{accept}({remainSpan}[0] >= {FormatCharLiteral(set.Value[0])} && {remainSpan}[0] <= {FormatCharLiteral(set.Value[1])})";
case RegexCharSetType.Set:
switch (set.Value[0])
{
case 's':
return $"{accept}char.IsWhiteSpace({remainSpan}[0])";
case 'w':
return $"{accept}{nameof(TextRegex.IsCharWord)}({remainSpan}[0])";
case 'd':
return $"{accept}char.IsDigit({remainSpan}[0])";
default:
break;
}
goto default;
default:
return string.Empty;
}
}
private static bool IsNamedFind(
RegexAstNode node
)
@@ -131,15 +162,37 @@ namespace StgSharp.RegularAnalysis.Text
case RegexElementLabel.UNIT:
_ = sc.AppendLine(@$"if({context.RemainSpan}[0] == {FormatCharLiteral(code[0])})")
.AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"goto {exit_label};")
.AppendLine("}");
break;
case RegexElementLabel.UNIT_SET:
IReadOnlyList<RegexCharSet> split = current.PayloadAs<RegexCharSetPayload>()
.Set;
RegexCharSet first_set = split[0];
for (int i = 1; i < split.Count - 1; i++) { }
RegexCharSet last_set = split[^1];
RegexCharSetPayload payload = current.PayloadAs<RegexCharSetPayload>();
IReadOnlyList<RegexCharSet> split = payload.Set;
bool accept = payload.Accept;
RegexCharSet _set = split[0];
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
for (int i = 1; i < split.Count - 1; i++)
{
_set = split[i];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
}
_set = split[^1];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}")
.AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"goto {exit_label};")
.AppendLine("}");
break;
case RegexElementLabel.UNIT_SPAN:
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({FormatStringLiteral(code)}))")
.AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"goto {exit_label};")
.AppendLine("}");
break;
default:
break;
}
} else