ngra string regex use ir as jit engine as well

This commit is contained in:
Youmu Liu
2026-06-15 18:08:14 +08:00
parent 2741b34583
commit 861b50575a
23 changed files with 352 additions and 795 deletions
@@ -26,14 +26,7 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using StgSharp.RegularAnalysis.Abstraction;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace StgSharp.RegularAnalysis.TextRegex
{
@@ -0,0 +1,242 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexIR"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.TextRegex
{
internal enum RegexIRCommand
{
Search = 0,
Jump = 1,
Compare = 2,
Check = 3,
Uncheck = 4,
Span = 5,
Define = 6,
Assign = 7,
Back = 8,
}
internal abstract class RegexIR
{
internal abstract RegexIRCommand Command { get; }
internal abstract void Execute();
}
/// <summary>
/// Searches for a certain string pattern or charset from current position.
/// </summary>
internal sealed class RegexSearchStringIR(
string pattern
) : RegexIR
{
public string Pattern { get; } = pattern;
internal override RegexIRCommand Command => RegexIRCommand.Search;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexSearchCharsetIR(
string charset
) : RegexIR
{
public string Charset { get; } = charset;
internal override RegexIRCommand Command => RegexIRCommand.Search;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexSearchCharIR(
char c
) : RegexIR
{
public char target { get; } = c;
internal override RegexIRCommand Command => RegexIRCommand.Search;
internal override void Execute()
{
throw new NotImplementedException();
}
}
/// <summary>
/// JUMP to a certain instruction index.
/// </summary>
/// <param name="target">
///
/// </param>
internal sealed class RegexJumpIR(
int target
) : RegexIR
{
public int TargetIndex { get; } = target;
internal override RegexIRCommand Command => RegexIRCommand.Jump;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexBackIR(
int index
) : RegexIR
{
public int Target { get; } = index;
internal override RegexIRCommand Command => RegexIRCommand.Back;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexCompareIR(
int success,
int fail
) : RegexIR
{
public int SuccessCase { get; } = success;
public int FailCase { get; } = fail;
internal override RegexIRCommand Command => RegexIRCommand.Compare;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexCheckIR : RegexIR
{
internal override RegexIRCommand Command => RegexIRCommand.Check;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexUncheckIR : RegexIR
{
internal override RegexIRCommand Command => RegexIRCommand.Check;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexSpanIR(
string name
) : RegexIR
{
public string Name { get; } = name;
internal override RegexIRCommand Command => RegexIRCommand.Span;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexDefineCommand(
string name
) : RegexIR
{
public string Name { get; } = name;
internal override RegexIRCommand Command => RegexIRCommand.Define;
internal override void Execute()
{
throw new NotImplementedException();
}
}
internal sealed class RegexAssignCommand<T>(
string name,
T value
) : RegexIR
{
public string Name { get; } = name;
public T Value { get; } = value;
internal override RegexIRCommand Command => RegexIRCommand.Assign;
internal override void Execute()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,54 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="RegexInterpreter.IRGenerate"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using StgSharp.RegularAnalysis.Abstraction;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.RegularAnalysis.TextRegex
{
public partial class RegexInterpreter
{
internal List<RegexIR> GenerateIR(
AbstractSyntaxTree<RegexAstNode, RegexElementLabel> tree
)
{
using TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new(tree);
while (enumerator.MoveNext())
{
if (true) { }
}
return [];
}
}
}
@@ -106,8 +106,8 @@ namespace StgSharp.RegularAnalysis.TextRegex
int length = 0;
RegexAstNode right = root.Right;
RegexAstNode left = root.Left;
if (left.EqualityTypeConvert != RegexElementLabel.UNIT_SPAN &&
left.EqualityTypeConvert != RegexElementLabel.UNIT) {
if (left.EqualityTypeConvert is not RegexElementLabel.UNIT_SPAN and
not RegexElementLabel.UNIT) {
return false;
}
string str = left.Value;
@@ -117,8 +117,8 @@ namespace StgSharp.RegularAnalysis.TextRegex
right.EqualityTypeConvert == RegexElementLabel.CONCAT)
{
left = right.Left;
if (left.EqualityTypeConvert != RegexElementLabel.UNIT_SPAN &&
left.EqualityTypeConvert != RegexElementLabel.UNIT)
if (left.EqualityTypeConvert is not RegexElementLabel.UNIT_SPAN and
not RegexElementLabel.UNIT)
{
break;
}
@@ -130,8 +130,8 @@ namespace StgSharp.RegularAnalysis.TextRegex
right = root.Right;
right.Parent = root;
}
if (right.EqualityTypeConvert == RegexElementLabel.UNIT_SPAN ||
right.EqualityTypeConvert == RegexElementLabel.UNIT)
if (right.EqualityTypeConvert is RegexElementLabel.UNIT_SPAN or
RegexElementLabel.UNIT)
{
root.Right = RegexAstNode.Empty;
buffer.Add(right.Value);
@@ -367,8 +367,6 @@ namespace StgSharp.RegularAnalysis.TextRegex
Cases[i].Parent = UnionEnd;
}
UnionEnd.Right = Cases[0];
TreeEnumerator<RegexAstNode, RegexElementLabel> enumerator = new TreeEnumerator<RegexAstNode, RegexElementLabel>(UnionBegin);
return UnionBegin;
}
@@ -62,7 +62,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
string regex
)
{
RegexInterpreter interpreter = new RegexInterpreter();
RegexInterpreter interpreter = new();
interpreter._source = regex;
bool isSuccess;
try
@@ -81,11 +81,12 @@ namespace StgSharp.RegularAnalysis.TextRegex
private void Analyze()
{
RegexTokenReader reader = new RegexTokenReader(_source);
RegexTokenReader reader = new(_source);
TokenParser<RegexElementLabel, RegexElementLabel> lexer = reader.Pipe(() => new RegexTokenParser());
while (lexer.TryReadToken(out Token<RegexElementLabel> token))
{
// Console.WriteLine(token.Value);
if ((token.Flag & RegexElementLabel.SEQUENCE) != 0)
{
// char or charset
@@ -68,6 +68,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
}
} else
{
Console.WriteLine("returns empty");
return Token<RegexElementLabel>.Empty;
}
}
@@ -82,7 +83,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
return false;
}
t = ReadToken();
return t == Token<RegexElementLabel>.Empty;
return t != Token<RegexElementLabel>.Empty;
}
}
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="RegexTokenReader"
// Project: StgSharp
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. All rights reserved.
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -45,7 +45,9 @@ namespace StgSharp.RegularAnalysis.TextRegex
public RegexTokenReader() { }
public RegexTokenReader(string source)
public RegexTokenReader(
string source
)
{
_source = source;
}
@@ -65,9 +67,11 @@ namespace StgSharp.RegularAnalysis.TextRegex
{
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.TextRegex
{
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.");
@@ -112,21 +118,24 @@ namespace StgSharp.RegularAnalysis.TextRegex
{
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,19 +150,25 @@ namespace StgSharp.RegularAnalysis.TextRegex
case '*' or '+':
int count = _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 '.':
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos, RegexElementLabel.UNIT);
return new Token<RegexElementLabel>(_source[(pos)..(pos + 1)], 0, pos,
RegexElementLabel.UNIT);
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)
{
@@ -161,7 +176,7 @@ namespace StgSharp.RegularAnalysis.TextRegex
return false;
}
t = ReadToken();
return Token<RegexElementLabel>.Empty == t;
return Token<RegexElementLabel>.Empty != t;
}
private Token<RegexElementLabel> ReadGroupBeginToken()