From f1688583cf57d07a9203518b0ef4f6f2acc8aa3d Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:27:56 +0800 Subject: [PATCH] import ast sys for regex runtime build --- ReadMe.md | 43 +- .../Abstraction/AbstractSyntaxTree.cs | 61 +++ .../Abstraction/CompileDepthState.cs | 73 ++++ .../Abstraction/CompileStack.cs | 367 ++++++++++++++++++ .../Abstraction/IScriptTokenReader.cs | 42 ++ .../Abstraction/ISyntaxNode.cs | 69 ++++ StgSharp.RegularAnalysis/Abstraction/Token.cs | 102 +++++ .../RegularAST/RegularAST.cs | 13 + .../RegularAST/SequenceElementType.cs | 50 +++ .../RegularMachine/Node.Branch.cs | 27 +- .../RegularMachine/Node.Sequence.cs | 16 +- .../RegularMachine/StateMachine.cs | 2 + .../StgSharp.RegularAnalysis.csproj | 4 + .../TextRegex/RegexAstLabel.cs | 47 +++ .../TextRegex/RegexLexer.cs | 262 +++++++++++++ 15 files changed, 1141 insertions(+), 37 deletions(-) create mode 100644 StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs create mode 100644 StgSharp.RegularAnalysis/Abstraction/CompileDepthState.cs create mode 100644 StgSharp.RegularAnalysis/Abstraction/CompileStack.cs create mode 100644 StgSharp.RegularAnalysis/Abstraction/IScriptTokenReader.cs create mode 100644 StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs create mode 100644 StgSharp.RegularAnalysis/Abstraction/Token.cs create mode 100644 StgSharp.RegularAnalysis/RegularAST/RegularAST.cs create mode 100644 StgSharp.RegularAnalysis/RegularAST/SequenceElementType.cs create mode 100644 StgSharp.RegularAnalysis/TextRegex/RegexAstLabel.cs create mode 100644 StgSharp.RegularAnalysis/TextRegex/RegexLexer.cs diff --git a/ReadMe.md b/ReadMe.md index a515a9c6..959961ed 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,7 +12,7 @@ StgSharp provides both low-level and high-level bindings to OpenGL, multimedia c ### StgSharp.Common -The main library containing core functionality: +The foundational library containing shared functionality: - **Mathematics**: High-performance linear algebra, matrix operations, and mathematical utilities - **Graphics**: OpenGL bindings, rendering pipeline, and graphics framework @@ -22,25 +22,21 @@ The main library containing core functionality: - **Entities**: Game entity system and behavior management - **Environment**: Platform abstraction and system integration -### StgSharp.Script +### StgSharp.Mathematics (Numeric) -General-purpose syntax analysis framework: +Numerics and linear algebra built on top of the core library: -- **Syntax Analysis Framework**: Provides a flexible framework for parsing and analyzing various programming languages -- **EXPRESS Language Support**: Specialized support for ISO 10303-11 EXPRESS language syntax parsing -- **Abstract Syntax Trees**: Language parsing and analysis infrastructure -- **Token Processing**: Lexical analysis and token management -- **Grammar Parsing**: Extensible grammar parsing and validation system +- **Matrix & Vector Types**: High-performance math primitives +- **Numeric Utilities**: Core numeric helpers and algorithms +- **SIMD-Friendly Kernels**: Data layouts optimized for hardware acceleration -### StgSharp.Model +### StgSharp.RegularAnalysis -Geometric model loading and interpretation: +Regular-language and parsing infrastructure (replaces the former Script module): -- **Geometric Model Loading**: Responsible for loading and interpreting geometric models from various formats -- **STEP Format Support**: Limited support for ISO 10303 STEP file format processing -- **Entity Management**: Model entity parsing and geometric data interpretation -- **Data Pipeline**: Efficient geometric data processing and transformation -- **Schema Validation**: Model structure validation and verification +- **Regex/Automata Core**: Regular expression processing and automata utilities +- **Parsing Primitives**: Reusable tokenizer and grammar building blocks +- **Analysis Pipeline**: Structured processing for language-like inputs ### StgSharp.Native @@ -51,14 +47,24 @@ Native library integration: - **Matrix Kernels**: Optimized matrix computation routines - **Context Management**: Graphics context and resource management +### StgSharp.Device + +Low-level device and port abstractions: + +- **Command Interfaces**: Command shapes and serialization contracts +- **Port Control**: Stream-oriented device access +- **Decoder/Response Models**: Protocol-level data handling + ### StgSharp.TerminalDialogue -Terminal-based user interface: +Terminal-based user interface application and components: -- **Interactive Terminal**: Command-line interface components +- **Interactive Terminal**: Command-line UI components - **Dialogue System**: User interaction and input handling - **Terminal Graphics**: Text-based UI rendering +> Note: The legacy Script module has been superseded by RegularAnalysis. The Model module is under refactoring and is currently out of the core framework. + ## Key Features ### High-Performance Computing @@ -129,6 +135,7 @@ StgSharp is currently in development and requires compilation from source. **NuG ### Building from Source 1. **Clone the repository**: + ```bash git clone https://github.com/Nitload-NSI/StgSharp.git cd StgSharp @@ -140,6 +147,7 @@ StgSharp is currently in development and requires compilation from source. **NuG - The native components will be automatically compiled 3. **Linux (Experimental)**: + ```bash # Build .NET components only # Note: Native components are not yet supported on Linux @@ -200,6 +208,7 @@ allocator.Free(handle); ## Documentation ### Technical Documentation + - [HLSF Allocator](StgSharp.Common/HighPerformance/Memory/InroductionToHLSF.md) - High-performance memory allocator documentation - [Native Library Naming](StgSharp.Native/naming.md) - Native library file naming conventions diff --git a/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs new file mode 100644 index 00000000..f7399ec4 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/AbstractSyntaxTree.cs @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="AbstractSyntaxTree" +// 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.Collections; + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Schema; + +namespace StgSharp.RegularAnalysis.Abstraction +{ + public sealed class AbstractSyntaxTree where TNode : ISyntaxNode + where TType : unmanaged + { + + private TNode _root; + + public int Count + { + get { return _allToken.Count; } + } + + public TNode Root => _root; + + public bool Contains( + TNode node + ) + { + return _allToken.Contains(node); + } + + private List _allToken = +new(); + + } +} diff --git a/StgSharp.RegularAnalysis/Abstraction/CompileDepthState.cs b/StgSharp.RegularAnalysis/Abstraction/CompileDepthState.cs new file mode 100644 index 00000000..8cbadce1 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/CompileDepthState.cs @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="CompileDepthState" +// Project: StgSharp +// AuthorGroup: Nitload Space +// Copyright (c) Nitload Space. 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.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.Abstraction +{ + public interface ICompileDepthState + { + + string CurrentState { get; set; } + + } + + public class CompileDepthMark + { + + internal CompileDepthMark(int operatorBegin, int operandBegin, int usage) + { + OperatorBegin = operatorBegin; + OperandBegin = operandBegin; + Usage = usage; + } + + internal CompileDepthMark(int operatorBegin, int operandBegin, int usage, ICompileDepthState stateCache) + { + OperatorBegin = operatorBegin; + OperandBegin = operandBegin; + Usage = usage; + StateCache = stateCache; + } + + public bool IsBeginOfBlock { get; internal set; } + + public ICompileDepthState StateCache { get; internal set; } + + public int OperandBegin { get; internal set; } + + public int OperatorBegin { get; internal set; } + + public int Usage { get; internal set; } + + } +} diff --git a/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs b/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs new file mode 100644 index 00000000..270363e7 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/CompileStack.cs @@ -0,0 +1,367 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="CompileStack" +// 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.Collections; + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.Abstraction +{ + public partial class CompileStack where TNode : ISyntaxNode + where TLabel : unmanaged + { + + private Token? _lastToken; + + private TNode[] _nodeArray = new TNode[4]; + private Token[] _operatorArray = new Token[4]; + private Token[] _tokenArray = new Token[4]; + + private int _nodeCount,_tokenCount, _operatorCount; + private RandomAccessibleStack _depthStack = new RandomAccessibleStack( + ); + + private RandomAccessibleStack _isNode = new RandomAccessibleStack( + 8); + private Stack> _statementCache = new Stack>(); + private TNode _lastNode; + + public CompileStack() + { + _depthStack.Push(new CompileDepthMark(0, 0, 0, null!)); + _statementCache.Push(new Stack()); + } + + public bool IsLastAddedOperator { get; private set; } + + public CompileDepthMark CurrentDepthMark + { + get => _depthStack.Peek(); + } + + public int Depth => _depthStack.Count; + + public int OperandCount => _isNode.Count; + + public int OperatorCount => _operatorCount; + + public int OperatorAheadOfDepth + { + get => OperatorCount - _depthStack.Peek().OperatorBegin; + } + + public int OperandAheadOfDepth + { + get => OperandCount - _depthStack.Peek().OperandBegin; + } + + public Stack StatementsInDepth + { + get => _statementCache.Peek(); + } + + public void DecreaseDepth() + { + CompileDepthMark mark = _depthStack.Pop(); + Stack statementsInDepth = _statementCache.Pop(); + } + + public bool GetOperandAt( + Index i, + out TNode operandNode, + out Token operandToken + ) + { + OperandIndex index = _isNode[i]; + if (index.IsNode) + { + operandNode = _nodeArray[index.Index]; + operandToken = Token.Empty; + return true; + } else + { + operandToken = _tokenArray[index.Index]; + operandNode = default!; + return false; + } + } + + public bool GetOperandAt( + CompileDepthMark depth, + Index i, + out Token operandToken, + out TNode operandNode + ) + { + OperandIndex index = _isNode[i]; + + _depthStack.Contains(depth); + if (index.IsNode) + { + operandNode = _nodeArray[index.Index]; + operandToken = Token.Empty; + return true; + } else + { + operandToken = _tokenArray[index.Index]; + operandNode = default!; + return false; + } + } + + public CompileDepthMark IncreaseDepth( + int usage + ) + { + CompileDepthMark mark = + new CompileDepthMark(OperatorCount, OperandCount, usage); + + _depthStack.Push(mark); + _statementCache.Push(new Stack()); + return mark; + } + + public TNode PackAllStatements() + { + if (StatementsInDepth.Count == 0) { + return TNode.Empty; + } + TNode end = StatementsInDepth.Peek(); + TNode first = end; + while (StatementsInDepth.Count > 0) + { + first = StatementsInDepth.Pop(); + end.PrependNode(first); + end = first; + } + return first; + } + + public bool PeekOperand( + out Token t, + out TNode n + ) + { + if (OperandAheadOfDepth <= 0) + { + t = Token.Empty; + n = TNode.Empty; + return false; + } + if (_isNode.Pop().IsNode) + { + t = Token.Empty; + n = _nodeArray[_nodeCount - 1]; + return true; + } else + { + t = _tokenArray[_tokenCount - 1]; + n = TNode.Empty; + return false; + } + } + + public Token PeekOperator() + { + if (OperatorAheadOfDepth > 0) { + return _operatorArray[_operatorCount - 1]; + } + return Token.Empty; + } + + public bool PopOperand( + out Token t, + out TNode n + ) + { + if (OperandAheadOfDepth <= 0) + { + t = Token.Empty; + n = TNode.Empty; + return false; + } + if (_isNode.Pop().IsNode) + { + t = Token.Empty; + n = _nodeArray[--_nodeCount]; + return true; + } else + { + t = _tokenArray[--_tokenCount]; + n = TNode.Empty; + return false; + } + } + + public Token PopOperator() + { + if (OperatorAheadOfDepth > 0) + { + _operatorCount--; + return _operatorArray[_operatorCount]; + } + return Token.Empty; + } + + public void PushOperand( + TNode node + ) + { + if (_nodeArray.Length == _nodeCount) { + Array.Resize(ref _nodeArray, _nodeArray.Length * 2); + } + _nodeArray[_nodeCount] = node; + _isNode.Push(new(true, _nodeCount)); + _nodeCount++; + IsLastAddedOperator = false; + } + + public void PushOperand( + Token token + ) + { + if (_tokenArray.Length == _tokenCount) { + Array.Resize(ref _tokenArray, _tokenArray.Length * 2); + } + _tokenArray[_tokenCount] = token; + _isNode.Push(new(false, _tokenCount)); + _tokenCount++; + IsLastAddedOperator = false; + } + + public void PushOperator( + Token token + ) + { + if (_operatorArray.Length == _operatorCount) { + Array.Resize(ref _operatorArray, _operatorArray.Length * 2); + } + _operatorArray[_operatorCount] = token; + _operatorCount++; + IsLastAddedOperator = true; + } + + public T StateOfCurrentDepth() where T : class, ICompileDepthState + { + return (CurrentDepthMark.StateCache as T)!; + } + + public bool TryPeekOperand( + out bool isNode, + out Token t, + out TNode n + ) + { + if (OperandAheadOfDepth <= 0) + { + t = Token.Empty; + n = TNode.Empty; + isNode = false; + return false; + } + if (_isNode.Pop().IsNode) + { + t = Token.Empty; + n = _nodeArray[_nodeCount - 1]; + isNode = true; + return true; + } else + { + t = _tokenArray[_tokenCount - 1]; + n = TNode.Empty; + isNode = false; + return false; + } + } + + public bool TryPeekOperator( + out Token op + ) + { + if (OperatorAheadOfDepth > 0) + { + op = _operatorArray[_operatorCount - 1]; + return true; + } + op = Token.Empty; + return false; + } + + public bool TryPopOperand( + out bool isNode, + out Token t, + out TNode n + ) + { + if (OperandAheadOfDepth <= 0) + { + t = Token.Empty; + n = TNode.Empty; + isNode = false; + return false; + } + if (_isNode.Pop().IsNode) + { + t = Token.Empty; + n = _nodeArray[--_nodeCount]; + isNode = true; + return true; + } else + { + t = _tokenArray[--_tokenCount]; + n = TNode.Empty; + isNode = false; + return true; + } + } + + public bool TryPopOperator( + out Token op + ) + { + if (OperatorAheadOfDepth > 0) + { + op = _operatorArray[--_operatorCount]; + return true; + } + op = Token.Empty; + return false; + } + + private record struct OperandIndex( + bool IsNode, + int Index + ); + + } +} diff --git a/StgSharp.RegularAnalysis/Abstraction/IScriptTokenReader.cs b/StgSharp.RegularAnalysis/Abstraction/IScriptTokenReader.cs new file mode 100644 index 00000000..cc83abd0 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/IScriptTokenReader.cs @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="IScriptTokenReader" +// 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. +// +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +namespace StgSharp.RegularAnalysis.Abstraction +{ + public interface IScriptTokenReader where TLabel : unmanaged + { + + bool IsEmpty { get; } + + Token ReadToken(); + + bool TryReadToken( + out Token t + ); + + } +} \ No newline at end of file diff --git a/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs b/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs new file mode 100644 index 00000000..020cbc65 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/ISyntaxNode.cs @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="ISyntaxNode" +// 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.Collections; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace StgSharp.RegularAnalysis.Abstraction +{ + public interface ISyntaxNode where TNode : ISyntaxNode + where TLabel : unmanaged + { + + long NodeFlag { get; } + + string CodeConvertTemplate { get; } + + TLabel EqualityTypeConvert { get; } + + TNode Previous { get; set; } + + TNode Next { get; set; } + + TNode Left { get; } + + TNode Right { get; } + + static abstract TNode Empty { get; } + + Token Source { get; } + + void AppendNode( + TNode nextToken + ); + + void PrependNode( + TNode previousNode + ); + + } +} diff --git a/StgSharp.RegularAnalysis/Abstraction/Token.cs b/StgSharp.RegularAnalysis/Abstraction/Token.cs new file mode 100644 index 00000000..074c87a8 --- /dev/null +++ b/StgSharp.RegularAnalysis/Abstraction/Token.cs @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="Token" +// 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.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.Abstraction +{ + public readonly struct Token where TLabel : unmanaged + { + + private static readonly Token EmptyToken = new Token(); + + public readonly int Column; + public readonly int Line; + public readonly string Value; + public readonly TLabel Flag; + + public Token( + string chars, + int lineNumber, + int columnNumber, + TLabel flag + ) + { + Value = chars; + Line = lineNumber; + Column = columnNumber; + Flag = flag; + } + + public static Token Empty => EmptyToken; + + public override bool Equals( + [NotNullWhen(true)] object? obj + ) + { + return base.Equals(obj); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Token ReLocate( + int line, + int column + ) + { + return new Token(Value, line, column, Flag); + } + + public static bool operator !=( + Token left, + Token right + ) + { + return left.Value.SequenceEqual(right.Value) && + left.Line == right.Line && + left.Column == right.Column && + left.Flag.Equals(right.Flag); + } + + public static bool operator ==( + Token left, + Token right + ) + { + return left.Value.SequenceEqual(right.Value) || + left.Line != right.Line || + left.Column != right.Column || + !(left.Flag.Equals(right.Flag)); + } + + } +} diff --git a/StgSharp.RegularAnalysis/RegularAST/RegularAST.cs b/StgSharp.RegularAnalysis/RegularAST/RegularAST.cs new file mode 100644 index 00000000..1bc9da1c --- /dev/null +++ b/StgSharp.RegularAnalysis/RegularAST/RegularAST.cs @@ -0,0 +1,13 @@ + +using StgSharp.RegularAnalysis.Abstraction; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.RegularAST +{ + internal class RegularAST : AbstractSyntaxTree { } +} diff --git a/StgSharp.RegularAnalysis/RegularAST/SequenceElementType.cs b/StgSharp.RegularAnalysis/RegularAST/SequenceElementType.cs new file mode 100644 index 00000000..bda189e9 --- /dev/null +++ b/StgSharp.RegularAnalysis/RegularAST/SequenceElementType.cs @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="SequenceElementType" +// 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.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.RegularAST +{ + internal class SequenceElementType : ITypeSource> + where T : unmanaged, INumber + { + + public bool IsConvertable( + SequenceElementType targetType + ) + { + throw new NotImplementedException(); + } + + } +} diff --git a/StgSharp.RegularAnalysis/RegularMachine/Node.Branch.cs b/StgSharp.RegularAnalysis/RegularMachine/Node.Branch.cs index bcb17ee4..be8865b4 100644 --- a/StgSharp.RegularAnalysis/RegularMachine/Node.Branch.cs +++ b/StgSharp.RegularAnalysis/RegularMachine/Node.Branch.cs @@ -36,9 +36,11 @@ using System.Threading.Tasks; namespace StgSharp.RegularAnalysis { - internal class RegularBranchNode : RegularStateNode + internal sealed class RegularBranchNode : RegularStateNode { + private int _afterBranch; + private int _lastBranch; private List _result; @@ -59,15 +61,26 @@ namespace StgSharp.RegularAnalysis out int label ) { - int pos = context.LastBranch.Peek(); - if (AvailableNodes.Length > _lastBranch) + if (context.StateCode == 0) { - // return measure result - label = 0; + // branch match + label = _afterBranch; + _ = context.LastBranch.Pop(); + _lastBranch = 0; return true; } - label = FailNodeIndex; - return false; + + // restore sequence position + int pos = context.LastBranch.Peek(); + context.Position = pos; + if (AvailableNodes.Length > _lastBranch) + { + label = FailNodeIndex; + return false; + } + _lastBranch++; + label = AvailableNodes[_lastBranch]; + return true; } } diff --git a/StgSharp.RegularAnalysis/RegularMachine/Node.Sequence.cs b/StgSharp.RegularAnalysis/RegularMachine/Node.Sequence.cs index 41c45c1c..d6b27eae 100644 --- a/StgSharp.RegularAnalysis/RegularMachine/Node.Sequence.cs +++ b/StgSharp.RegularAnalysis/RegularMachine/Node.Sequence.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; namespace StgSharp.RegularAnalysis { - internal class RegularSequenceNode : RegularStateNode + internal sealed class RegularSequenceNode : RegularStateNode { private string _sequence; @@ -17,20 +18,9 @@ namespace StgSharp.RegularAnalysis RegularStateNode former, RegularContext context ) - { - return true; - } - - public override bool TryTransaction( - ReadOnlySpan nodeSpan, - RegularContext context, - out int label - ) { int pos = context.Position + 1; - if (true) { } - label = -1; - return false; + return context.CurrentCharSpan[pos.._sequence.Length].SequenceEqual(_sequence); } } diff --git a/StgSharp.RegularAnalysis/RegularMachine/StateMachine.cs b/StgSharp.RegularAnalysis/RegularMachine/StateMachine.cs index 62046ca5..ef55a864 100644 --- a/StgSharp.RegularAnalysis/RegularMachine/StateMachine.cs +++ b/StgSharp.RegularAnalysis/RegularMachine/StateMachine.cs @@ -127,6 +127,8 @@ namespace StgSharp.RegularAnalysis public int Position { get; set; } = -1; + public int StateCode { get; set; } = 0; + public ReadOnlySpan CurrentCharSpan => Source.AsSpan()[Begin..Position]; public string Source { get; init; } diff --git a/StgSharp.RegularAnalysis/StgSharp.RegularAnalysis.csproj b/StgSharp.RegularAnalysis/StgSharp.RegularAnalysis.csproj index 0153ae4b..e85687f1 100644 --- a/StgSharp.RegularAnalysis/StgSharp.RegularAnalysis.csproj +++ b/StgSharp.RegularAnalysis/StgSharp.RegularAnalysis.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexAstLabel.cs b/StgSharp.RegularAnalysis/TextRegex/RegexAstLabel.cs new file mode 100644 index 00000000..921e59ae --- /dev/null +++ b/StgSharp.RegularAnalysis/TextRegex/RegexAstLabel.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="RegexAstLabel" +// 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 RegexAstLabel + { + + CHAR, + CHAR_SET, + GROUP_NAME, + GROUP_BEGIN, + GROUP_END, + COUNT, + + } +} diff --git a/StgSharp.RegularAnalysis/TextRegex/RegexLexer.cs b/StgSharp.RegularAnalysis/TextRegex/RegexLexer.cs new file mode 100644 index 00000000..ea1af2e8 --- /dev/null +++ b/StgSharp.RegularAnalysis/TextRegex/RegexLexer.cs @@ -0,0 +1,262 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="RegexLexer" +// 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.Runtime.InteropServices; +using System.Security.Permissions; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.RegularAnalysis.TextRegex +{ + internal class RegexLexer : IScriptTokenReader + { + + private static string _source; + + private int position = 0; + + public bool IsEmpty => string.IsNullOrEmpty(_source) || position >= _source.Length; + + public Token ReadToken() + { + int pos = position; + switch (_source[pos]) + { + case '\\': + if (pos + 1 == _source.Length) { + throw new InvalidOperationException("Unclosed char"); + } + position = pos + 2; + return new Token(_source[(pos)..(pos + 2)], 0, pos, + RegexAstLabel.CHAR); + case '[': + for (int i = pos + 1; i < _source.Length; i++) + { + if (_source[i] == ']' && _source[i - 1] != '\\') + { + int length = (i - pos - 1); + position = i + 1; + return new Token(_source[(pos - 1)..(i - 1)], 0, + position, RegexAstLabel.CHAR_SET); + } + } + throw new InvalidOperationException("Unclosed character set"); + case '(': + + // very comlex here + return ReadGroupBeginToken(); + case ')': + position = pos + 1; + return new Token(_source[(pos)..1], 0, pos, + RegexAstLabel.GROUP_END); + case '{': + for (int i = pos + 1; i < _source.Length; i++) + { + if (_source[i] == '}') + { + position = i + 1; + return new Token(_source[(pos)..(i - 1)], 0, pos, + RegexAstLabel.COUNT); + } + } + throw new InvalidOperationException("Unclosed count specifier"); + case '*' or '+': + int count = _source[pos + 1] == '?' ? 2 : 1; + position = pos + count; + return new Token(_source[(pos)..(pos + count)], 0, pos, + RegexAstLabel.COUNT); + case '?': + position = pos + 1; + return new Token(_source[(pos)..(pos + 1)], 0, pos, + RegexAstLabel.COUNT); + case '.': + return new Token(_source[(pos)..(pos + 1)], 0, pos, + RegexAstLabel.CHAR_SET); + default: + position = pos + 1; + return new Token(_source[(pos)..(pos + 1)], 0, pos, + RegexAstLabel.CHAR); + } + } + + public bool TryReadToken( + out Token t + ) + { + if (IsEmpty) + { + t = Token.Empty; + return false; + } + t = ReadToken(); + return Token.Empty == t; + } + + private Token ReadGroupBeginToken() + { + if (_source is null) { + throw new InvalidOperationException("Source is null."); + } + + int start = position; + + if (start >= _source.Length || _source[start] != '(') { + throw new InvalidOperationException("ReadGroupBeginToken called when current char is not '('."); + } + + // Case 1: plain capturing group "(" + if (start + 1 >= _source.Length || _source[start + 1] != '?') + { + position = start + 1; + return new Token("(", 0, start, RegexAstLabel.GROUP_BEGIN); + } + + // From here we have "(?" + if (start + 2 >= _source.Length) + { + throw new InvalidOperationException("Unfinished group prefix '(?'."); + } + + char c2 = _source[start + 2]; + + // Case 2: non-capturing group "(?:" + if (c2 == ':') + { + position = start + 3; + return new Token("(?:", 0, start, RegexAstLabel.GROUP_BEGIN); + } + + // Assertions (write the first-level cases, but not supported yet) + if (c2 == '=') + { + // "(?=" + position = start + 3; + throw new NotSupportedException("Positive lookahead '(?=...)' is not supported yet."); + } + if (c2 == '!') + { + // "(?!" + position = start + 3; + throw new NotSupportedException("Negative lookahead '(?!...)' is not supported yet."); + } + + // Named capturing group or lookbehind starts with "(?<" + if (c2 == '<') + { + if (start + 3 >= _source.Length) { + throw new InvalidOperationException("Unfinished group prefix '(?<'."); + } + + char c3 = _source[start + 3]; + + // Lookbehind prefixes: "(?<=" and "(?" + int nameStart = start + 3; + + // Read name until '>' + int i = nameStart; + + // Name must start with [A-Za-z_] + if (i >= _source.Length) + { + throw new InvalidOperationException("Unfinished named group prefix."); + } + + char first = _source[i]; + if (!(first == '_' || char.IsLetter(first))) { + throw new InvalidOperationException($"Invalid named group name start '{first}' at position {i}."); + } + + i++; + + while (i < _source.Length) + { + char ch = _source[i]; + if (ch == '>') + { + break; + } + + if (!(ch == '_' || char.IsLetterOrDigit(ch))) { + throw new InvalidOperationException($"Invalid character '{ch}' in group name at position {i}."); + } + + i++; + } + + if (i >= _source.Length || _source[i] != '>') { + throw new InvalidOperationException("Unclosed named group prefix; missing '>'."); + } + + // Consume "(?" + int consumedLen = (i - start) + 1; // include '>' + string text = _source.Substring(start, consumedLen); + position = start + consumedLen; + + return new Token(text, 0, start, RegexAstLabel.GROUP_BEGIN); + } + + // Optional: comments "(?#...)" or inline options "(?i:...)" etc. + // First-level cases listed but not supported yet: + if (c2 == '#') + { + position = start + 3; + throw new NotSupportedException("Comment group '(?#...)' is not supported yet."); + } + + // Inline options: (?i:...), (?m:...), (?-i:...), (?im), etc. + // Too many dialect differences; reserve the prefix but mark unsupported. + if (char.IsLetter(c2) || c2 == '-') + { + // We don't know how long the option spec is here; do NOT advance position too much. + // Keep position at '(' so caller can decide how to handle, or just throw. + position = start; + throw new NotSupportedException("Inline option groups like '(?i:...)' are not supported yet."); + } + + // Unknown "(?X" prefix + position = start; + throw new InvalidOperationException($"Unknown or unsupported group prefix starting at position {start}: '{_source.Substring(start, Math.Min(4, _source.Length - start))}'"); + } + + } +}