diff --git a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/DefaultTokenTypesJsonStringProvider.cs b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/DefaultTokenTypesJsonStringProvider.cs
new file mode 100644
index 0000000..97a05e6
--- /dev/null
+++ b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/DefaultTokenTypesJsonStringProvider.cs
@@ -0,0 +1,9 @@
+using HydraScript.Domain.FrontEnd.Lexer;
+
+namespace HydraScript.Infrastructure.LexerRegexGenerator;
+
+internal class DefaultTokenTypesJsonStringProvider :
+ ITokenTypesJsonStringProvider
+{
+ public string TokenTypesJsonString => TokenTypesJson.String;
+}
\ No newline at end of file
diff --git a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/HydraScript.Infrastructure.LexerRegexGenerator.csproj b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/HydraScript.Infrastructure.LexerRegexGenerator.csproj
index 890cbc7..bd90347 100644
--- a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/HydraScript.Infrastructure.LexerRegexGenerator.csproj
+++ b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/HydraScript.Infrastructure.LexerRegexGenerator.csproj
@@ -14,4 +14,8 @@
+
+
+
+
diff --git a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/ITokenTypesJsonStringProvider.cs b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/ITokenTypesJsonStringProvider.cs
new file mode 100644
index 0000000..666f0d9
--- /dev/null
+++ b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/ITokenTypesJsonStringProvider.cs
@@ -0,0 +1,6 @@
+namespace HydraScript.Infrastructure.LexerRegexGenerator;
+
+public interface ITokenTypesJsonStringProvider
+{
+ public string TokenTypesJsonString { get; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/PatternGenerator.cs b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/PatternGenerator.cs
index afab806..781b3cf 100644
--- a/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/PatternGenerator.cs
+++ b/src/Infrastructure/HydraScript.Infrastructure.LexerRegexGenerator/PatternGenerator.cs
@@ -1,9 +1,6 @@
-using System.Collections.Immutable;
using System.Text;
using System.Text.Json;
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace HydraScript.Infrastructure.LexerRegexGenerator;
@@ -11,86 +8,32 @@ namespace HydraScript.Infrastructure.LexerRegexGenerator;
[Generator]
public partial class PatternGenerator : IIncrementalGenerator
{
- private const string AttributeSourceCode = @"//
-
-namespace HydraScript.Infrastructure;
-
-[System.AttributeUsage(System.AttributeTargets.Class)]
-public class PatternContainerAttribute(string json) : System.Attribute
- where T : HydraScript.Domain.FrontEnd.Lexer.IGeneratedRegexContainer
-{
- public string Json { get; } = json;
-}
-";
+ public ITokenTypesJsonStringProvider Provider { get; init; } = new DefaultTokenTypesJsonStringProvider();
public void Initialize(IncrementalGeneratorInitializationContext context)
{
- context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
- "PatternContainerAttribute.g.cs",
- SourceText.From(AttributeSourceCode, Encoding.UTF8)));
-
- var provider = context.SyntaxProvider
- .ForAttributeWithMetadataName(
- "HydraScript.Infrastructure.PatternContainerAttribute`1",
- static (s, _) => IsSyntaxTargetForGeneration(s),
- static (ctx, _) => GetTypeDeclarationForSourceGen(ctx))
- .Where(static x => x is not null)
- .Select(static (x, _) => x!);
-
- context.RegisterImplementationSourceOutput(provider.Collect(), GenerateCode);
- }
-
- private static bool IsSyntaxTargetForGeneration(SyntaxNode node) =>
- node is ClassDeclarationSyntax candidate &&
- candidate.Modifiers.Any(SyntaxKind.PartialKeyword) &&
- candidate.Modifiers.Any(SyntaxKind.InternalKeyword);
-
- private static RegexContainerInfo? GetTypeDeclarationForSourceGen(
- GeneratorAttributeSyntaxContext context)
- {
- var attribute = context.Attributes.FirstOrDefault();
- if (attribute is null)
- return null;
- var visitable = (ClassDeclarationSyntax)context.TargetNode;
- var json = attribute.ConstructorArguments.First().Value!.ToString()!;
- return new RegexContainerInfo(
- ClassName: visitable.Identifier.Text,
- json);
- }
+ var tokenTypes = JsonSerializer.Deserialize(
+ Provider.TokenTypesJsonString,
+ PatternGeneratorContext.Default.IEnumerableTokenType)!
+ .OrderBy(x => x.Priority)
+ .Concat([new TokenType("ERROR", @"\S+", int.MaxValue)]);
+ var pattern = string.Join('|', tokenTypes.Select(t => t.GetNamedRegex()));
- private static void GenerateCode(
- SourceProductionContext context,
- ImmutableArray containerInfos)
- {
- foreach (var info in containerInfos)
- {
- var tokenTypes = JsonSerializer.Deserialize(
- info.Json,
- PatternGeneratorContext.Default.IEnumerableTokenType)!
- .OrderBy(x => x.Priority)
- .Concat([new TokenType("ERROR", @"\S+", int.MaxValue)]);
- var pattern = string.Join('|', tokenTypes.Select(t => t.GetNamedRegex()));
-
- var code = $@"//
+ var code = $@"//
using System.Diagnostics.CodeAnalysis;
namespace HydraScript.Infrastructure;
-internal partial class {info.ClassName}
+internal partial class PatternContainer
{{
[StringSyntax(StringSyntaxAttribute.Regex)]
- public const string Pattern =
- """"""
- {pattern}
- """""";
+ public const string Value = """"""{pattern}"""""";
}}
";
- context.AddSource($"{info.ClassName}.g.cs", SourceText.From(code, Encoding.UTF8));
- }
- }
- private record RegexContainerInfo(
- string ClassName,
- string Json);
+ context.RegisterPostInitializationOutput(ctx => ctx.AddSource(
+ "PatternContainer.g.cs",
+ SourceText.From(code, Encoding.UTF8)));
+ }
}
\ No newline at end of file
diff --git a/src/Infrastructure/HydraScript.Infrastructure/GeneratedRegexContainer.cs b/src/Infrastructure/HydraScript.Infrastructure/GeneratedRegexContainer.cs
index 67df795..62b08b3 100644
--- a/src/Infrastructure/HydraScript.Infrastructure/GeneratedRegexContainer.cs
+++ b/src/Infrastructure/HydraScript.Infrastructure/GeneratedRegexContainer.cs
@@ -3,9 +3,8 @@
namespace HydraScript.Infrastructure;
-[PatternContainer(TokenTypesJson.String)]
internal partial class GeneratedRegexContainer : IGeneratedRegexContainer
{
- [GeneratedRegex("""(?[/]{2}.*)|(?[0-9]+[.][0-9]+)|(?[0-9]+)|(?null)|(?true|false)|(?\"(\\.|[^"\\])*\")|(?let|const|function|if|else|while|break|continue|return|as|type)|(?[+]{1,2}|[-]|[*]|[/]|[%]|([!]|[=])[=]|([<]|[>])[=]?|[!]|[|]{2}|[&]{2}|[~]|[:]{2})|(?[a-zA-Z][a-zA-Z0-9]*)|(?[?])|(?[:])|(?[;])|(?[=])|(?[,])|(?[{])|(?[}])|(?[(])|(?[)])|(?[.])|(?[[])|(?[]])|(?\S+)""")]
+ [GeneratedRegex(PatternContainer.Value)]
public static partial Regex GetRegex();
}
\ No newline at end of file
diff --git a/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests.csproj b/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests.csproj
index 1f0b0ca..8b0b58e 100644
--- a/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests.csproj
+++ b/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests.csproj
@@ -8,6 +8,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
+
diff --git a/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/PatternGeneratorTests.cs b/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/PatternGeneratorTests.cs
index 10840d0..7fd07bf 100644
--- a/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/PatternGeneratorTests.cs
+++ b/tests/HydraScript.Infrastructure.LexerRegexGenerator.Tests/PatternGeneratorTests.cs
@@ -1,31 +1,54 @@
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
+using NSubstitute;
using Xunit;
namespace HydraScript.Infrastructure.LexerRegexGenerator.Tests;
public class PatternGeneratorTests
{
+ [StringSyntax(StringSyntaxAttribute.Json)]
+ private const string JsonStringReplacement =
+ """
+ [
+ {
+ "tag": "Test2",
+ "pattern": "test2",
+ "priority": 2
+ },
+ {
+ "tag": "Test1",
+ "pattern": "test1",
+ "priority": 1
+ }
+ ]
+ """;
+
[Fact]
public void Initialize_PatternContainerMarked_CorrectlyGenerated()
{
- var inputCompilation = CreateCompilation(
- """
- using System.Text.RegularExpressions;
- using HydraScript.Domain.FrontEnd.Lexer;
+ var provider = Substitute.For();
+ provider.TokenTypesJsonString.Returns(JsonStringReplacement);
+ var generator = new PatternGenerator
+ {
+ Provider = provider
+ };
+ GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- namespace HydraScript.Infrastructure;
+ driver = driver.RunGeneratorsAndUpdateCompilation(CreateCompilation(string.Empty), out var outputCompilation,
+ out var diagnostics);
+ Debug.Assert(diagnostics.IsEmpty);
+ Debug.Assert(outputCompilation.SyntaxTrees.Count() == 2);
- [PatternContainer("[{ \"tag\": \"Number\", \"pattern\": \"[0-9]+\", \"priority\": 2 }, { \"tag\": \"Word\", \"pattern\": \"[a-zA-Z]+\", \"priority\": 1 }]")]
- internal partial class TestPatternContainer : IGeneratedRegexContainer
- {
- public static Regex GetRegex() => throw new NotImplementedException();
- }
- """);
+ var runResult = driver.GetRunResult();
- const string expectedSource =
+ var generatedFileSyntax = runResult.GeneratedTrees
+ .Single(t => t.FilePath.EndsWith("PatternContainer.g.cs"));
+
+ const string expectedSource =
""""
//
@@ -33,30 +56,14 @@ internal partial class TestPatternContainer : IGeneratedRegexContainer
namespace HydraScript.Infrastructure;
-internal partial class TestPatternContainer
+internal partial class PatternContainer
{
[StringSyntax(StringSyntaxAttribute.Regex)]
- public const string Pattern =
- """
- (?[a-zA-Z]+)|(?[0-9]+)|(?\S+)
- """;
+ public const string Value = """(?test1)|(?test2)|(?\S+)""";
}
"""";
- var generator = new PatternGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
-
- driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation,
- out var diagnostics);
- Debug.Assert(diagnostics.IsEmpty);
- Debug.Assert(outputCompilation.SyntaxTrees.Count() == 3);
-
- var runResult = driver.GetRunResult();
-
- var generatedFileSyntax = runResult.GeneratedTrees
- .Single(t => t.FilePath.EndsWith("TestPatternContainer.g.cs"));
-
Assert.Equal(
expectedSource,
generatedFileSyntax.GetText().ToString(),
diff --git a/tests/HydraScript.Tests/Unit/Infrastructure/GeneratedRegexContainerTests.cs b/tests/HydraScript.Tests/Unit/Infrastructure/GeneratedRegexContainerTests.cs
deleted file mode 100644
index 895b5b8..0000000
--- a/tests/HydraScript.Tests/Unit/Infrastructure/GeneratedRegexContainerTests.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using HydraScript.Infrastructure;
-using Xunit;
-
-namespace HydraScript.Tests.Unit.Infrastructure;
-
-public class GeneratedRegexContainerTests
-{
- [Fact]
- public void GetRegex_Generated_ManualIsUpToDate() =>
- GeneratedRegexContainer.Pattern.Trim().Should().Be(
- GeneratedRegexContainer.GetRegex().ToString(),
- "because В атрибут GeneratedRegex не подставлена актуальная сгенерированная регулярка");
-}
\ No newline at end of file