diff --git a/ReadMe.md b/ReadMe.md index 1e106800..6900daee 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,16 +1,18 @@ -# StgSharp +# Nitload -![StgSharp Logo](STG%23LOGO.png) +![Nitload Logo](STG%23LOGO.png) -StgSharp is an experimental .NET framework for graphics, numerical computing, language analysis, and other performance-sensitive applications. It began as the foundation of a next-generation STG (shoot 'em up) engine, but the current repository focuses on reusable low-level infrastructure rather than a complete, ready-to-use game engine. +Nitload (formerly StgSharp) is an experimental .NET framework for graphics, numerical computing, language analysis, and other performance-sensitive applications. It began as the foundation of a next-generation STG (shoot 'em up) engine, but the current repository focuses on reusable low-level infrastructure rather than a complete, ready-to-use game engine. + +The managed libraries now use the `Nitload.*` namespace and project prefix. Repository URLs, the logo filename, and some legacy test artifacts still retain the StgSharp name. ## Overview -The framework combines managed C# APIs with a C native library. Its current work includes OpenGL bindings and rendering infrastructure, generic matrix and vector types, SIMD-accelerated native kernels, custom allocators and collections, regular-language analysis, and state-oriented UI infrastructure. StgSharp targets .NET 8; platform and architecture coverage varies by module, with Windows and Linux as the principal native targets. +The framework combines managed C# APIs with a C native library. Its current work includes OpenGL bindings and rendering infrastructure, generic matrix and vector types, SIMD-accelerated native kernels, custom allocators and collections, regular-language analysis, and state-oriented UI infrastructure. Nitload targets .NET 8; platform and architecture coverage varies by module, with Windows and Linux as the principal native targets. ## Core Modules -### StgSharp.Common +### Nitload.Common The foundational library containing shared functionality: @@ -20,7 +22,7 @@ The foundational library containing shared functionality: - **Pipeline and State**: Processing pipelines and reusable state-machine primitives - **Environment**: Platform abstraction and system integration -### StgSharp.Mathematics (Numeric) +### Nitload.Mathematics (Numeric) Numerics and linear algebra built on top of the core library: @@ -28,7 +30,7 @@ Numerics and linear algebra built on top of the core library: - **Numeric Utilities**: Core numeric helpers and algorithms - **SIMD-Friendly Kernels**: Data layouts optimized for hardware acceleration -### StgSharp.RegularAnalysis +### Nitload.RegularAnalysis Nitload General Regular Analysis (NGRA) infrastructure for recognizing and processing regular languages: @@ -36,9 +38,9 @@ Nitload General Regular Analysis (NGRA) infrastructure for recognizing and proce - **Parsing Primitives**: Reusable tokenizer and grammar building blocks - **Analysis Pipeline**: Structured processing for language-like inputs -NGRA is a foundation for higher-level language tooling. It does not replace `StgSharp.Script`; the planned Script implementation depends on NGRA and has not started yet. The source currently under `StgSharp.Script` is retained from the earlier EXPRESS implementation and is not part of the active core solution. +NGRA is a foundation for higher-level language tooling. It does not replace `Nitload.Script`; the planned Script implementation depends on NGRA and has not started yet. The source currently under `Nitload.Script` is retained from the earlier EXPRESS implementation and is not part of the active core solution. -### StgSharp.Graphics +### Nitload.Graphics Managed graphics infrastructure built on Common and Mathematics: @@ -47,7 +49,7 @@ Managed graphics infrastructure built on Common and Mathematics: - **Shader Support**: Shader compilation, program management, and shader-generation utilities - **Window Integration**: GLFW-based window and input access -### StgSharp.Native +### Nitload.Native Native library integration: @@ -56,7 +58,7 @@ Native library integration: - **Matrix Kernels**: Optimized matrix computation routines - **Platform Runtime**: Native thread and platform support for Windows and Linux -### StgSharp.TerminalDialogue +### Nitload.TerminalDialogue Terminal-based user interface application and components: @@ -64,7 +66,7 @@ Terminal-based user interface application and components: - **Dialogue System**: User interaction and input handling - **Terminal Graphics**: Text-based UI rendering -> Note: `StgSharp.Script` is planned as a consumer of NGRA and has not started yet. Its existing EXPRESS sources belong to the earlier implementation. `StgSharp.Model` is currently an empty placeholder while its design is being reconsidered. +> Note: `Nitload.Script` is planned as a consumer of NGRA and has not started yet. Its existing EXPRESS sources belong to the earlier implementation. `Nitload.Model` is currently an empty placeholder while its design is being reconsidered. ## Key Features @@ -113,7 +115,7 @@ The benchmark reports normalized time per allocation/free operation. Each iterat ### Data Processing - **NGRA**: Regex analysis, intermediate representation, optimization, and source generation -- **EXPRESS (legacy/inactive)**: The repository retains an earlier experimental EXPRESS parser/compiler under `StgSharp.Script` +- **EXPRESS (legacy/inactive)**: The repository retains an earlier experimental EXPRESS parser/compiler under `Nitload.Script` - **Script (planned)**: A future language layer intended to build on NGRA; development has not started ## Requirements @@ -125,7 +127,7 @@ The benchmark reports normalized time per allocation/free operation. Each iterat ## Installation -StgSharp is currently in development and requires compilation from source. **NuGet packages are not yet available** - you must build the project from source code. +Nitload is currently in development and requires compilation from source. **NuGet packages are not yet available** - you must build the project from source code. ### Prerequisites @@ -159,7 +161,7 @@ StgSharp is currently in development and requires compilation from source. **NuG dotnet build Nitload.sln ``` - Managed builds copy an existing native binary into their output directory. They do not invoke CMake automatically, so build `StgSharp.Native` first when native functionality is required. + Managed builds copy an existing native binary into their output directory. They do not invoke CMake automatically, so build `Nitload.Native` first when native functionality is required. ### Build Configuration @@ -168,7 +170,7 @@ StgSharp is currently in development and requires compilation from source. **NuG ### Notes -- CMake is the maintained build path for `StgSharp.Native`; the checked-in presets primarily target Clang +- CMake is the maintained build path for `Nitload.Native`; the checked-in presets primarily target Clang - The Visual Studio C project may be opened with MSVC tooling, but MSVC IntelliSense behavior and MSVC-produced binaries are not maintained or guaranteed - Windows and Linux platform implementations exist; actual feature and architecture coverage may differ - x86-64 currently has the most complete optimized kernel coverage @@ -187,8 +189,8 @@ StgSharp is currently in development and requires compilation from source. **NuG ### Matrix Operations ```csharp -using StgSharp.HighPerformance.Memory; -using StgSharp.Mathematics.Numeric; +using Nitload.Common.HighPerformance.Memory; +using Nitload.Mathematics.Numeric; // Matrix storage is allocated explicitly from a native-memory arena. using var allocator = new TwoLayerSegregatedFitAllocator(64 * 1024 * 1024); @@ -207,7 +209,7 @@ General matrix arithmetic does not currently provide operator overloads. Because ### Memory Management ```csharp -using StgSharp.HighPerformance.Memory; +using Nitload.Common.HighPerformance.Memory; // Create a 64 MiB TLSF arena using var allocator = new TwoLayerSegregatedFitAllocator(64 * 1024 * 1024); @@ -231,7 +233,7 @@ allocator.Free(handle); ## Contributing -StgSharp is developed by Nitload Space. Contributions are welcome, particularly in: +Nitload is developed by Nitload Space. Contributions are welcome, particularly in: - Performance optimizations - Cross-platform compatibility @@ -240,7 +242,7 @@ StgSharp is developed by Nitload Space. Contributions are welcome, particularly ## License -StgSharp is licensed under the MIT License. See [LICENSE](LICENSE) for details. +Nitload is licensed under the MIT License. See [LICENSE](LICENSE) for details. ## Future Plans diff --git a/src/Nitload.Native/README.md b/src/Nitload.Native/README.md index d9b10776..1b19e6fe 100644 --- a/src/Nitload.Native/README.md +++ b/src/Nitload.Native/README.md @@ -1,4 +1,4 @@ -# StgSharp.Native +# Nitload.Native ## COMPILE diff --git a/src/Nitload.RegularAnalysis/Text/RegexAstNode.cs b/src/Nitload.RegularAnalysis/Text/RegexAstNode.cs index a953d59b..68db8b59 100644 --- a/src/Nitload.RegularAnalysis/Text/RegexAstNode.cs +++ b/src/Nitload.RegularAnalysis/Text/RegexAstNode.cs @@ -101,6 +101,27 @@ namespace Nitload.RegularAnalysis.Text { return node is null || ReferenceEquals(node, Empty); } + + /// + /// Recognizes zero-or-more repetitions of one non-negated Any atom, including lazy + /// repetition. Callers inspect the COUNT payload's IsGreedy flag separately. + /// + public static bool IsDotStar(RegexAstNode? node) + { + if (node?.Payload is not RegexCountPayload { IsStar: true }) { + return false; + } + + bool left_empty = IsNullOrEmpty(node.Left); + bool right_empty = IsNullOrEmpty(node.Right); + if (left_empty == right_empty) { + return false; + } + + RegexAstNode operand = left_empty ? node.Right : node.Left; + return operand.Payload is RegexCharSetPayload { IsAny: true, Accept: true } set && + set.Set[0].Accept; + } /**/ public void PrependNode(RegexAstNode previousNode) diff --git a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs index 14958b43..26da0a18 100644 --- a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs +++ b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs @@ -7,15 +7,7 @@ using Microsoft.CodeAnalysis.CSharp; using Nitload.RegularAnalysis.Abstraction; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection.Metadata.Ecma335; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace Nitload.RegularAnalysis.Text { @@ -27,21 +19,24 @@ namespace Nitload.RegularAnalysis.Text in SequenceEmitter sc, in List> func_list, in SourceGenContext context, + in ExitLabel exit_label = default, bool is_find = false - ) { RegexAstNode root = ast; if (root.Label == RegexElementLabel.EPSILON) { return; } + if (TryGenerateSpecialSource(root, sc, func_list, context, exit_label)) { + return; + } RegexElementLabel op = root.Label & (RegexElementLabel.VAST_OPERATOR); if (op != 0) { switch (op) { case RegexElementLabel.CONCAT: - GenerateConcat(root, sc, func_list, context); + GenerateConcat(root, sc, func_list, context, exit_label); break; case RegexElementLabel.COUNT: GenerateCount(root, sc, func_list, context); @@ -64,25 +59,20 @@ namespace Nitload.RegularAnalysis.Text switch (op) { case RegexElementLabel.UNIT: - - // TODO(NGRA): Emit the remaining-span length guard, literal comparison, - // cursor advance, and failure transfer for one character. + GenerateUnit(root, sc, context, exit_label); break; case RegexElementLabel.UNIT_SET: - - // TODO(NGRA): Emit the remaining-span length guard, charset predicate, - // cursor advance, and failure transfer. + GenerateUnitSet(root, sc, context, exit_label); break; case RegexElementLabel.UNIT_SPAN: - - // TODO(NGRA): Emit StartsWith for the complete literal span and advance by - // the literal length; integrate is_find candidate retry semantics. + GenerateUnitSpan(root, sc, context, exit_label); break; default: - - // TODO(NGRA): Diagnose malformed leaf nodes instead of generating no code. break; } + + // TODO(NGRA): Integrate is_find candidate search and continuation retries. + // Leaf emission currently matches only at the active cursor. } } @@ -120,228 +110,105 @@ namespace Nitload.RegularAnalysis.Text case RegexCharSetType.Single: return $"{accept}({FormatStringLiteral(set.Value)}.{nameof(MemoryExtensions.Contains)}({remain_span}[0]))"; case RegexCharSetType.Range: + if (set.Value.Length != 2) { + throw new InvalidOperationException("A charset range requires two endpoints."); + } return $"{accept}({remain_span}[0] >= {FormatCharLiteral(set.Value[0])} && {remain_span}[0] <= {FormatCharLiteral(set.Value[1])})"; case RegexCharSetType.Set: - switch (set.Value[0]) + switch (set.Value) { - case 's': + case "s": return $"{accept}char.IsWhiteSpace({remain_span}[0])"; - case 'w': - return $"{accept}{nameof(TextRegex.IsCharWord)}({remain_span}[0])"; - case 'd': + case "w": + return $"{accept}{Text_Regex}.{nameof(TextRegex.IsCharWord)}({remain_span}[0])"; + case "d": return $"{accept}char.IsDigit({remain_span}[0])"; default: break; } goto default; + case RegexCharSetType.Any: + return set.Accept ? "true" : "false"; default: - - // TODO(NGRA): Unsupported/empty charset rules must become an analyzer - // diagnostic; returning an empty expression produces invalid generated C#. - return string.Empty; + throw new NotSupportedException($"Unsupported charset rule: {set.Type} ({set.Value})."); } } - private static bool IsNamedFind( - RegexAstNode node - ) - { - // (?.*)abc - - if (node is null) - { - return false; - } - if ((node.Label & RegexElementLabel.CONCAT) != 0) { - return false; - } - RegexAstNode group = node.Left; - - // TODO(NGRA): Validate the normalized CONCAT/GROUP/COUNT shape with Empty sentinels - // before dereferencing children; this helper currently assumes every edge exists. - if ((group.Label & RegexElementLabel.GROUP_BEGIN) == 0) - { - return false; - } - RegexAstNode count = group.Right; - - // .* - return (count.Label & RegexElementLabel.COUNT) != 0 && - (count.Right.Label & RegexElementLabel.UNIT_SINGLE) != 0 && - count.Right.Source.Source == "."; - } - #endregion - #region basic verb generate + #region UNIT direct matching - private static void GenerateAlt( - RegexAstNode node, + private static void GenerateUnit( + RegexAstNode value, [NotNull] in SequenceEmitter sc, - in List> func_list, - in SourceGenContext context + in SourceGenContext context, + in ExitLabel exit ) { - RegexAstNode current = node.Right; - - // TODO(NGRA-NAMING): Reserve exclusive names for future ALT cursor/capture snapshots; - // their lifetime extends through retry labels, not just the candidate's emitted block. - ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto); - - // TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal - // shape and failure continuation are not wired yet. - while (RegexAstNode.IsNullOrEmpty(current)) - { - RegexElementLabel op = current.Label & RegexElementLabel.SEQUENCE; - if (op != 0) - { - string code = current.SourceCode; - switch (op) - { - case RegexElementLabel.UNIT: - - // TODO(NGRA): Guard against an empty remaining span before indexing it. - _ = 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: - - // TODO(NGRA): Guard the remaining span, handle empty/Any sets, and - // validate negated-set composition before emitting this predicate. - RegexCharSetPayload payload = current.PayloadAs(); - IReadOnlyList 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: - - // TODO(NGRA): Advance by code.Length rather than one character and - // preserve the ALT rollback cursor on failure. - string liteal = FormatStringLiteral(code); - _ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({liteal}))") - .AppendLine("{") - .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice({code.Length});") - .AppendLine($@"goto {exit_label};") - .AppendLine("}"); - - break; - default: - - // TODO(NGRA): Route unsupported ALT candidates through the recursive - // matcher or report a source-generation diagnostic. - break; - } - - // TODO(NGRA): Advance to the next ALT candidate after a scalar candidate - // misses; the current sequence branch does not update current. - } else - { - GenerateMethodSource(current, sc, func_list, context); - current = current.Next; - } + string literal = value.Value; + if (literal.Length != 1) { + throw new InvalidOperationException( + $"UNIT requires one decoded character, but received {literal.Length}."); } - // TODO(NGRA): Emit the all-alternatives-failed continuation before the shared success - // label, including restoration of the entry cursor and capture state. - _ = sc.AppendLine($@"{exit_label}: {{ }}"); + string remain_span = context.RemainSpan; + _ = sc.AppendLine($"if ({remain_span}.IsEmpty || {remain_span}[0] != {FormatCharLiteral(literal[0])})") + .AppendLine("{") + .AppendLine($"goto {exit.GetLabelName()};") + .AppendLine("}") + .AppendLine($"{remain_span} = {remain_span}.Slice(1);"); } - private static void GenerateGroup( - RegexAstNode node, + private static void GenerateUnitSet( + RegexAstNode value, [NotNull] in SequenceEmitter sc, - in List> func_list, - in SourceGenContext context + in SourceGenContext context, + in ExitLabel exit ) { - RegexAstNode left = node.Left; - RegexAstNode right = node.Right; - - RegexGroupPayload config = node.PayloadAs(); - - // TODO(NGRA-NAMING): Reserve exclusive names for generated group snapshots and capture - // temporaries. A capture's user-provided name is not a unique generated local name. - - // TODO(NGRA): Select the owned group body using Empty-sentinel checks, snapshot its - // start cursor, and restore it when the child matcher fails. - if (left is not null) - { - GenerateMethodSource(left, sc, func_list, context); - } else - if (right is not null) { - GenerateMethodSource(right, sc, func_list, context); + RegexCharSetPayload payload = value.PayloadAs(); + string[] rules = new string[payload.Set.Count]; + for (int i = 0; i < rules.Length; i++) { + rules[i] = GenerateCharSetExpression(payload.Set[i]); } - string group_name = config.Name; - - // TODO(NGRA): Allocate numeric/named capture slots and emit the successful capture - // span. Non-capturing groups still need a rollback scope but no stored capture. - throw new NotImplementedException(); + // Combine rule-level complements before applying the enclosing charset complement. + // An empty union accepts nothing; its complement accepts any available character. + string predicate = rules.Length == 0 ? "false" : string.Join(" || ", rules); + string mismatch = payload.Accept ? $"!({predicate})" : $"({predicate})"; + string remain_span = context.RemainSpan; + _ = sc.AppendLine($"if ({remain_span}.IsEmpty || {mismatch})") + .AppendLine("{") + .AppendLine($"goto {exit.GetLabelName()};") + .AppendLine("}") + .AppendLine($"{remain_span} = {remain_span}.Slice(1);"); } - private static void GenerateConcat( - RegexAstNode node, + private static void GenerateUnitSpan( + RegexAstNode value, [NotNull] in SequenceEmitter sc, - in List> func_list, - in SourceGenContext context + in SourceGenContext context, + in ExitLabel exit ) { - RegexAstNode left = node.Left; - RegexAstNode right = node.Right; - - if (left is not null) - { - // find - if ((left.Label & RegexElementLabel.COUNT) == RegexElementLabel.COUNT && - (left.Right.Label & RegexElementLabel.UNIT_SINGLE) == RegexElementLabel.UNIT_SINGLE && - left.Right.Source.Source == "." && - right is not null) - { - // TODO(NGRA): Emit the unnamed FIND candidate loop and retry the right subtree - // until it succeeds or no anchor candidate remains. - GenerateMethodSource(right, sc, func_list, context, true); - } else if (IsNamedFind(node)) - { - if (right is not null) - { - // TODO(NGRA): Emit named FIND retry and capture the text preceding the - // successful anchor candidate. - GenerateMethodSource(right, sc, func_list, context, true); - } else - { - // TODO(NGRA): Capture the remaining input for a terminal named dot-star. - } - } else - { - GenerateMethodSource(left, sc, func_list, context); - if (right is not null) { - GenerateMethodSource(right, sc, func_list, context); - } - } + string literal = value.Value; + if (literal.Length == 0) { + throw new InvalidOperationException("UNIT_SPAN requires a non-empty literal."); } - // TODO(NGRA): Normalize ownership so the right subtree is emitted exactly once. It is - // currently reachable both inside the ordinary CONCAT branch and here. - if (right is not null) - { - GenerateMethodSource(right, sc, func_list, context); - } + // StartsWith also rejects input shorter than the decoded literal. + string remain_span = context.RemainSpan; + _ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(literal)}))") + .AppendLine("{") + .AppendLine($"goto {exit.GetLabelName()};") + .AppendLine("}") + .AppendLine($"{remain_span} = {remain_span}.Slice({literal.Length});"); } + #endregion + + #region UNIT count matching + private const int flattened_unit_count_threshold = 32; private static void GenerateUnitCount( @@ -435,19 +302,15 @@ namespace Nitload.RegularAnalysis.Text int additional_limit = max < 0 ? -1 : max - min; if (is_greedy && additional_limit != 0) { - if (additional_limit < 0) - { - _ = sc.AppendLine($"while (!{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal})") - .AppendLine("{") - .AppendLine($"{remain_span} = {remain_span}.Slice(1);") - .AppendLine("}"); - } else - { - _ = sc.AppendLine($"for (int {additional_count} = 0; {additional_count} < {additional_limit} && !{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal}; {additional_count}++)") - .AppendLine("{") - .AppendLine($"{remain_span} = {remain_span}.Slice(1);") - .AppendLine("}"); - } + _ = additional_limit < 0 ? + sc.AppendLine($"while (!{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal})") + .AppendLine("{") + .AppendLine($"{remain_span} = {remain_span}.Slice(1);") + .AppendLine("}") : + sc.AppendLine($"for (int {additional_count} = 0; {additional_count} < {additional_limit} && !{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal}; {additional_count}++)") + .AppendLine("{") + .AppendLine($"{remain_span} = {remain_span}.Slice(1);") + .AppendLine("}"); } else if (!is_greedy && additional_limit != 0) { // Lazy COUNT deliberately stops at Min. Its optional tail is consumed only when @@ -673,12 +536,156 @@ namespace Nitload.RegularAnalysis.Text } } - private static void GenerateCount( + #endregion + + #region UNIT find matching + + // TODO(NGRA): Add UNIT, UNIT_SET, and UNIT_SPAN candidate search emitters here. + // Wire is_find dispatch and continuation retries when FIND matching is implemented. + + #endregion + + #region Operator generation + + private static void GenerateAlt( + RegexAstNode node, + [NotNull] in SequenceEmitter sc, + in List> func_list, + in SourceGenContext context + ) + { + RegexAstNode current = node.Right; + + // TODO(NGRA-NAMING): Reserve exclusive names for future ALT cursor/capture snapshots; + // their lifetime extends through retry labels, not just the candidate's emitted block. + ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto); + + // TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal + // shape and failure continuation are not wired yet. + while (RegexAstNode.IsNullOrEmpty(current)) + { + RegexElementLabel op = current.Label & RegexElementLabel.SEQUENCE; + if (op != 0) + { + string code = current.SourceCode; + switch (op) + { + case RegexElementLabel.UNIT: + + // TODO(NGRA): Guard against an empty remaining span before indexing it. + _ = 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: + + // TODO(NGRA): Guard the remaining span, handle empty/Any sets, and + // validate negated-set composition before emitting this predicate. + RegexCharSetPayload payload = current.PayloadAs(); + IReadOnlyList 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: + + // TODO(NGRA): Advance by code.Length rather than one character and + // preserve the ALT rollback cursor on failure. + string literal = FormatStringLiteral(code); + _ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({literal}))") + .AppendLine("{") + .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice({code.Length});") + .AppendLine($@"goto {exit_label};") + .AppendLine("}"); + + break; + default: + + // TODO(NGRA): Route unsupported ALT candidates through the recursive + // matcher or report a source-generation diagnostic. + break; + } + + // TODO(NGRA): Advance to the next ALT candidate after a scalar candidate + // misses; the current sequence branch does not update current. + } else + { + GenerateMethodSource(current, sc, func_list, context); + current = current.Next; + } + } + + // TODO(NGRA): Emit the all-alternatives-failed continuation before the shared success + // label, including restoration of the entry cursor and capture state. + _ = sc.AppendLine($@"{exit_label}: {{ }}"); + } + + private static void GenerateGroup( + RegexAstNode node, + [NotNull] in SequenceEmitter sc, + in List> func_list, + in SourceGenContext context + ) + { + RegexAstNode left = node.Left; + RegexAstNode right = node.Right; + + RegexGroupPayload config = node.PayloadAs(); + + // TODO(NGRA-NAMING): Reserve exclusive names for generated group snapshots and capture + // temporaries. A capture's user-provided name is not a unique generated local name. + + // TODO(NGRA): Select the owned group body using Empty-sentinel checks, snapshot its + // start cursor, and restore it when the child matcher fails. + if (left is not null) + { + GenerateMethodSource(left, sc, func_list, context); + } else + if (right is not null) { + GenerateMethodSource(right, sc, func_list, context); + } + + string group_name = config.Name; + + // TODO(NGRA): Allocate numeric/named capture slots and emit the successful capture + // span. Non-capturing groups still need a rollback scope but no stored capture. + throw new NotImplementedException(); + } + + private static void GenerateConcat( RegexAstNode node, [NotNull] in SequenceEmitter sc, in List> func_list, in SourceGenContext context, - in ExitLabel exit + in ExitLabel exit_label = default + ) + { + if (!RegexAstNode.IsNullOrEmpty(node.Left)) { + GenerateMethodSource(node.Left, sc, func_list, context, exit_label); + } + if (!RegexAstNode.IsNullOrEmpty(node.Right)) { + GenerateMethodSource(node.Right, sc, func_list, context, exit_label); + } + } + + private static void GenerateCount( + RegexAstNode node, + [NotNull] in SequenceEmitter sc, + in List> func_list, + in SourceGenContext context ) { RegexAstNode value = RegexAstNode.IsNullOrEmpty(node.Left) ? node.Right : node.Left; diff --git a/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenSpecial.cs b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenSpecial.cs new file mode 100644 index 00000000..1fbeb591 --- /dev/null +++ b/src/Nitload.RegularAnalysis/Text/TextRegexSourceGen.GenSpecial.cs @@ -0,0 +1,111 @@ +// ----------------------------------------------------------------------------- +// file="TextRegexSourceGen.GenSpecial" +// Project: Nitload +// Copyright (c) Nitload. +// SPDX-License-Identifier: MIT +// ----------------------------------------------------------------------------- + +using Nitload.RegularAnalysis.Abstraction; + +namespace Nitload.RegularAnalysis.Text +{ + internal partial class TextRegexSourceGen + { + + private static bool TryGenerateSpecialSource( + RegexAstNode node, + in SequenceEmitter sc, + in List> func_list, + in SourceGenContext context, + in ExitLabel exit_label + ) + { + // A special rule owns the entire matched subtree. Returning false leaves emission + // to the general path; returning true prevents that subtree from being emitted twice. + return node.Label switch + { + RegexElementLabel.CONCAT => TryGenerateFindConcat(node, sc, func_list, context, exit_label), + _ => false, + }; + } + + #region FIND concatenation + + private static bool TryGenerateFindConcat( + RegexAstNode node, + in SequenceEmitter sc, + in List> func_list, + in SourceGenContext context, + in ExitLabel exit_label + ) + { + RegexAstNode left = node.Left; + RegexAstNode right = node.Right; + if (RegexAstNode.IsNullOrEmpty(left)) { + return false; + } + + // Existing FIND dispatch scaffold; candidate search and retries are not implemented. + // TODO(NGRA): Use the COUNT payload's IsGreedy flag to order FIND candidates. + if (RegexAstNode.IsDotStar(left) && !RegexAstNode.IsNullOrEmpty(right)) + { + // TODO(NGRA): Emit the unnamed FIND candidate loop and retry the right subtree + // until it succeeds or no anchor candidate remains. + GenerateMethodSource(right, sc, func_list, context, exit_label, true); + return true; + } + + if (IsNamedFind(node)) + { + if (!RegexAstNode.IsNullOrEmpty(right)) + { + // TODO(NGRA): Emit named FIND retry and capture the text preceding the + // successful anchor candidate. + GenerateMethodSource(right, sc, func_list, context, exit_label, true); + } else + { + // TODO(NGRA): Capture the remaining input for a terminal named dot-star. + } + return true; + } + + return false; + } + + private static bool IsNamedFind( + RegexAstNode node + ) + { + // (?.*)abc + + if (RegexAstNode.IsNullOrEmpty(node) || node.Label != RegexElementLabel.CONCAT) { + return false; + } + RegexAstNode group = node.Left; + if (RegexAstNode.IsNullOrEmpty(group) || + group.Payload is not RegexGroupPayload { IsCapturing: true } config || + string.IsNullOrEmpty(config.Name)) { + return false; + } + + bool left_empty = RegexAstNode.IsNullOrEmpty(group.Left); + bool right_empty = RegexAstNode.IsNullOrEmpty(group.Right); + return left_empty != right_empty && + RegexAstNode.IsDotStar(left_empty ? group.Right : group.Left); + } + + #endregion + + #region Repeated capture rules + + // TODO(NGRA): Recognize and implement repeated captures such as (?.*){m,n} + // and (?.*a){m,n}. Keep these distinct from (?.*)a FIND concatenation. + // A later repetition may need to reopen an earlier repetition's inner search, restoring + // its cursor, candidate position, and capture state. Do not claim these subtrees in + // TryGenerateSpecialSource until the complete retry/rollback strategy is implemented. + // An escaped star is a literal and must not be classified as dot-star repetition. + + #endregion + + } +} diff --git a/src/README.md b/src/README.md index 30cc5ca6..c18375f8 100644 --- a/src/README.md +++ b/src/README.md @@ -1,22 +1,22 @@ # Source Projects -This directory contains the production source code, native runtime, supporting applications, and benchmarks for StgSharp. Most managed projects target .NET 8. The native project is built separately with CMake and provides platform and SIMD functionality consumed by managed projects. +This directory contains the production source code, native runtime, supporting applications, and benchmarks for Nitload. Most managed projects target .NET 8. The native project is built separately with CMake and provides platform and SIMD functionality consumed by managed projects. ## Directory map | Directory | Purpose | | --- | --- | -| `StgSharp.Common` | Shared collections, memory management, threading, pipelines, platform abstractions, and other foundational APIs. | -| `StgSharp.Mathematics` | Numeric types, vectors, matrices, geometry, and managed access to accelerated math operations. | -| `StgSharp.Graphics` | OpenGL bindings, rendering infrastructure, shaders, textures, windows, and input integration. | -| `StgSharp.Native` | C native runtime, GLFW/STBI integration, allocators, platform code, and optimized SIMD/matrix kernels. See its own `README.md` for native build details. | -| `StgSharp.RegularAnalysis` | NGRA regular-language analysis, regex processing, intermediate representations, and source-generation infrastructure. | -| `StgSharp.UserInterface` | State-oriented user-interface framework and its incremental source generator. | -| `StgSharp.TerminalDialogue` | Terminal user-interface components and an interactive terminal application. | -| `StgSharp.Benchmark` | BenchmarkDotNet workloads for measuring selected runtime and allocation behavior. | -| `StgSharp.Script` | Retained sources from the earlier EXPRESS implementation. The planned Script layer has not started and is expected to build on NGRA. | -| `StgSharp.Model` | Placeholder project whose design is being reconsidered. | -| `StgSharp.Tools` | Small retained comparison and inspection artifacts; it is not currently a buildable project. | +| `Nitload.Common` | Shared collections, memory management, threading, pipelines, platform abstractions, and other foundational APIs. | +| `Nitload.Mathematics` | Numeric types, vectors, matrices, geometry, and managed access to accelerated math operations. | +| `Nitload.Graphics` | OpenGL bindings, rendering infrastructure, shaders, textures, windows, and input integration. | +| `Nitload.Native` | C native runtime, GLFW/STBI integration, allocators, platform code, and optimized SIMD/matrix kernels. See its own `README.md` for native build details. | +| `Nitload.RegularAnalysis` | NGRA regular-language analysis, regex processing, intermediate representations, and source-generation infrastructure. | +| `Nitload.UserInterface` | State-oriented user-interface framework and its incremental source generator. | +| `Nitload.TerminalDialogue` | Terminal user-interface components and an interactive terminal application. | +| `Nitload.Benchmark` | BenchmarkDotNet workloads for measuring selected runtime and allocation behavior. | +| `Nitload.Script` | Retained sources from the earlier EXPRESS implementation. The planned Script layer has not started and is expected to build on NGRA. | +| `Nitload.Model` | Placeholder project whose design is being reconsidered. | +| `Nitload.Tools` | Small retained comparison and inspection artifacts; it is not currently a buildable project. | ## Build notes diff --git a/tools/Nitload.GenerateGL/README.md b/tools/Nitload.GenerateGL/README.md index c825d52c..69db9860 100644 --- a/tools/Nitload.GenerateGL/README.md +++ b/tools/Nitload.GenerateGL/README.md @@ -1,9 +1,13 @@ -# StgSharp.GenerateGL +# Nitload.GenerateGL -`StgSharp.GenerateGL` generates the StgSharp desktop OpenGL C# bindings from the Khronos `gl.xml` registry. +`Nitload.GenerateGL` generates the Nitload desktop OpenGL C# bindings from the Khronos `gl.xml` registry. The current target is OpenGL 4.6 Core. The generator does not emit OpenGL ES or mix extension entry points into the core API. `gl.xml` is the authoritative generation input; the retained `gl.h` is reference material only. +## Namespace migration + +The project and directory are named `Nitload.GenerateGL`, but the implementation namespace and generated-source templates still contain `StgSharp.*`. Update the templates in `Generation/OpenGlGenerator.cs` to emit `Nitload.Graphics.OpenGL` and import `Nitload.Mathematics.Numeric.Graphics` before regenerating the renamed graphics library. The CLI commands below use the current project paths; they do not automatically migrate generated namespaces. + ## Usage Start the interactive CLI: diff --git a/tools/Nitload.GenerateGL/xml/README.md b/tools/Nitload.GenerateGL/xml/README.md index 32166f51..07a71b33 100644 --- a/tools/Nitload.GenerateGL/xml/README.md +++ b/tools/Nitload.GenerateGL/xml/README.md @@ -1,6 +1,6 @@ # Khronos OpenGL Registry input -This directory intentionally does not track the third-party Khronos registry files. Before building or running `StgSharp.GenerateGL`, supply a registry snapshot from the canonical [KhronosGroup/OpenGL-Registry](https://github.com/KhronosGroup/OpenGL-Registry) repository. +This directory intentionally does not track the third-party Khronos registry files. Before building or running `Nitload.GenerateGL`, supply a registry snapshot from the canonical [KhronosGroup/OpenGL-Registry](https://github.com/KhronosGroup/OpenGL-Registry) repository. 1. Clone or download one coherent revision of `KhronosGroup/OpenGL-Registry`. 2. Copy the contents of its `xml/` directory directly into this directory. diff --git a/tools/README.md b/tools/README.md index aa6a27ae..e1e00783 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,14 +1,14 @@ # Development Tools -This directory contains repository-maintenance and source-generation programs. Tools are kept outside `src` because they help build or maintain StgSharp but are not shipped as part of the runtime libraries. +This directory contains repository-maintenance and source-generation programs. Tools are kept outside `src` because they help build or maintain Nitload but are not shipped as part of the runtime libraries. ## Directory map | Directory | Purpose | | --- | --- | -| `StgSharp.GenerateGL` | Reads the Khronos `gl.xml` registry, projects the OpenGL 4.6 Core API, analyzes function families, and generates the managed OpenGL bindings used by `StgSharp.Graphics`. | +| `Nitload.GenerateGL` | Reads the Khronos `gl.xml` registry, projects the OpenGL 4.6 Core API, analyzes function families, and generates the managed OpenGL bindings used by `Nitload.Graphics`. | -`StgSharp.GenerateGL` has its own `README.md` with its pipeline, naming rules, and interactive commands. The common direct-generation command is: +`Nitload.GenerateGL` has its own `README.md` with its pipeline, naming rules, and interactive commands. The common direct-generation command is: ```powershell dotnet run --project tools/Nitload.GenerateGL/Nitload.GenerateGL.csproj -- generate all src/Nitload.Graphics/OpenGL/Generated