diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cd967fc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d0d7a46 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj", "SimpleStateMachine.StructuralSearch.Action/"] +RUN dotnet restore "SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj" +COPY . . +WORKDIR "/src/SimpleStateMachine.StructuralSearch.Action" +RUN dotnet build "SimpleStateMachine.StructuralSearch.Action.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "SimpleStateMachine.StructuralSearch.Action.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "SimpleStateMachine.StructuralSearch.Action.dll"] diff --git a/SimpleStateMachine.StructuralSearch.Action/ActionInputs.cs b/SimpleStateMachine.StructuralSearch.Action/ActionInputs.cs new file mode 100644 index 0000000..85050f0 --- /dev/null +++ b/SimpleStateMachine.StructuralSearch.Action/ActionInputs.cs @@ -0,0 +1,58 @@ +using CommandLine; + +namespace SimpleStateMachine.StructuralSearch.Action; + + public class ActionInputs + { + string _repositoryName = null!; + string _branchName = null!; + + public ActionInputs() + { + if (Environment.GetEnvironmentVariable("GREETINGS") is { Length: > 0 } greetings) + { + Console.WriteLine(greetings); + } + } + + [Option('o', "owner", + Required = true, + HelpText = "The owner, for example: \"dotnet\". Assign from `github.repository_owner`.")] + public string Owner { get; set; } = null!; + + [Option('n', "name", + Required = true, + HelpText = "The repository name, for example: \"samples\". Assign from `github.repository`.")] + public string Name + { + get => _repositoryName; + set => ParseAndAssign(value, str => _repositoryName = str); + } + + [Option('b', "branch", + Required = true, + HelpText = "The branch name, for example: \"refs/heads/main\". Assign from `github.ref`.")] + public string Branch + { + get => _branchName; + set => ParseAndAssign(value, str => _branchName = str); + } + + [Option('d', "dir", + Required = true, + HelpText = "The root directory to start recursive searching from.")] + public string Directory { get; set; } = null!; + + [Option('w', "workspace", + Required = true, + HelpText = "The workspace directory, or repository root directory.")] + public string WorkspaceDirectory { get; set; } = null!; + + static void ParseAndAssign(string? value, Action assign) + { + if (value is { Length: > 0 } && assign is not null) + { + assign(value.Split("/")[^1]); + } + } + } \ No newline at end of file diff --git a/SimpleStateMachine.StructuralSearch.Action/Program.cs b/SimpleStateMachine.StructuralSearch.Action/Program.cs new file mode 100644 index 0000000..3e72de0 --- /dev/null +++ b/SimpleStateMachine.StructuralSearch.Action/Program.cs @@ -0,0 +1,105 @@ +using System.Text; +using SimpleStateMachine.StructuralSearch.Action; +using System.Web; +using CommandLine; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileSystemGlobbing; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using static CommandLine.Parser; + +using IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices((_, services) => + { + + }) + .Build(); + +static TService Get(IHost host) + where TService : notnull => + host.Services.GetRequiredService(); + +static async Task StartAnalysisAsync(ActionInputs inputs, IHost host) +{ + // using ProjectWorkspace workspace = Get(host); + using CancellationTokenSource tokenSource = new(); + + Console.CancelKeyPress += delegate { tokenSource.Cancel(); }; + + // var projectAnalyzer = Get(host); + + Matcher matcher = new(); + matcher.AddIncludePatterns(new[] { "**/*.csproj", "**/*.vbproj" }); + + // Dictionary metricData = new(StringComparer.OrdinalIgnoreCase); + var projects = matcher.GetResultsInFullPath(inputs.Directory); + + foreach (var project in projects) + { + // var metrics = + // await projectAnalyzer.AnalyzeAsync( + // workspace, project, tokenSource.Token); + // + // foreach (var (path, metric) in metrics) + // { + // metricData[path] = metric; + // } + } + + // var updatedMetrics = false; + // var title = ""; + // StringBuilder summary = new(); + // if (metricData is { Count: > 0 }) + // { + // var fileName = "CODE_METRICS.md"; + // var fullPath = Path.Combine(inputs.Directory, fileName); + // var logger = Get(host).CreateLogger(nameof(StartAnalysisAsync)); + // var fileExists = File.Exists(fullPath); + // + // logger.LogInformation( + // $"{(fileExists ? "Updating" : "Creating")} {fileName} markdown file with latest code metric data."); + // + // summary.AppendLine( + // title = + // $"{(fileExists ? "Updated" : "Created")} {fileName} file, analyzed metrics for {metricData.Count} projects."); + // + // foreach (var (path, _) in metricData) + // { + // summary.AppendLine($"- *{path}*"); + // } + // + // var contents = metricData.ToMarkDownBody(inputs); + // await File.WriteAllTextAsync( + // fullPath, + // contents, + // tokenSource.Token); + // + // updatedMetrics = true; + // } + // else + // { + // summary.Append("No metrics were determined."); + // } + // + // // https://docs.github.com/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter + // Console.WriteLine($"::set-output name=updated-metrics::{updatedMetrics}"); + // Console.WriteLine($"::set-output name=summary-title::{title}"); + // Console.WriteLine($"::set-output name=summary-details::{summary}"); + + Environment.Exit(0); +} + +var parser = Default.ParseArguments(() => new ActionInputs(), args); +parser.WithNotParsed( + errors => + { + Get(host) + .CreateLogger("DotNet.GitHubAction.Program") + .LogError( + string.Join(Environment.NewLine, errors.Select(error => error.ToString()))); + + Environment.Exit(2); + }); + +await parser.WithParsedAsync(options => StartAnalysisAsync(options, host)); +await host.RunAsync(); \ No newline at end of file diff --git a/SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj b/SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj new file mode 100644 index 0000000..7b29f5a --- /dev/null +++ b/SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + enable + enable + Windows + + + + + + + + + + + + diff --git a/SimpleStateMachine.StructuralSearch.sln b/SimpleStateMachine.StructuralSearch.sln index e4bd165..dba3167 100644 --- a/SimpleStateMachine.StructuralSearch.sln +++ b/SimpleStateMachine.StructuralSearch.sln @@ -9,6 +9,19 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.Structur EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.StructuralSearch.Sandbox", "src\SimpleStateMachine.StructuralSearch.Sandbox\SimpleStateMachine.StructuralSearch.Sandbox.csproj", "{263ABF7D-9728-4224-A584-5412E158D4BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.StructuralSearch.Action", "SimpleStateMachine.StructuralSearch.Action\SimpleStateMachine.StructuralSearch.Action.csproj", "{E22FFF76-E929-4E01-B2B3-4B9283705EDE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6CB879CC-E497-41C0-AEBD-864E9D3807A6}" + ProjectSection(SolutionItems) = preProject + Dockerfile = Dockerfile + .dockerignore = .dockerignore + .gitignore = .gitignore + LICENSE = LICENSE + README.md = README.md + global.json = global.json + action.yml = action.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +44,10 @@ Global {263ABF7D-9728-4224-A584-5412E158D4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {263ABF7D-9728-4224-A584-5412E158D4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {263ABF7D-9728-4224-A584-5412E158D4BB}.Release|Any CPU.Build.0 = Release|Any CPU + {E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..ca6c334 --- /dev/null +++ b/action.yml @@ -0,0 +1,43 @@ +name: 'Structural search' +description: 'A Github action that maintains a CODE_METRICS.md file, reporting cyclomatic complexity, maintainability index, etc.' +branding: + icon: sliders + color: purple +inputs: + owner: + description: 'The owner of the repo. Assign from github.repository_owner. Example, "dotnet".' + required: true + name: + description: 'The repository name. Example, "samples".' + required: true + branch: + description: 'The branch name. Assign from github.ref. Example, "refs/heads/main".' + required: true + dir: + description: 'The root directory to work from. Example, "path/to/code".' + required: true + workspace: + description: 'The workspace directory.' + required: false + default: '/github/workspace' +outputs: + summary-title: + description: 'The title of the code metrics action.' + summary-details: + description: 'A detailed summary of all the projects that were flagged.' + updated-metrics: + description: 'A boolean value, indicating whether or not the CODE_METRICS.md was updated as a result of running this action.' +runs: + using: 'docker' + image: 'Dockerfile' + args: + - '-o' + - ${{ inputs.owner }} + - '-n' + - ${{ inputs.name }} + - '-b' + - ${{ inputs.branch }} + - '-d' + - ${{ inputs.dir }} + - '-w' + - ${{ inputs.workspace }} diff --git a/src/SimpleStateMachine.StructuralSearch.Sandbox/Expr.cs b/src/SimpleStateMachine.StructuralSearch.Sandbox/Expr.cs index 5f72bd0..f72d2f4 100644 --- a/src/SimpleStateMachine.StructuralSearch.Sandbox/Expr.cs +++ b/src/SimpleStateMachine.StructuralSearch.Sandbox/Expr.cs @@ -137,6 +137,7 @@ public double Invoke() BinaryOperatorType.Mul => Left.Invoke() * Right.Invoke(), BinaryOperatorType.Div => Left.Invoke() / Right.Invoke(), BinaryOperatorType.Sub => Left.Invoke() - Right.Invoke(), + _ => throw new ArgumentOutOfRangeException() }; } } diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml index 4c6daaa..2f78c66 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml @@ -20,7 +20,7 @@ $var$ = $value1$; FindRules: - $sign$ In ("Is", "==", "!=", "is not") - - $value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value") + - $value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value") ReplaceTemplate: |- $var$ = $value1$ ?? $value2$; ReplaceRules: diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml index c673f23..673dc0e 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml @@ -19,7 +19,7 @@ $var$ = $value1$; FindRules: - $sign$ In ("Is", "==", "!=", "is not") - - $value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value") + - $value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value") ReplaceTemplate: |- $var$ = $value1$ ?? $value2$; ReplaceRules: diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/NullUnionOperator.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/NullUnionOperator.txt index ca18854..c626822 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/NullUnionOperator.txt +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/NullUnionOperator.txt @@ -1,2 +1,2 @@ $sign$ In ("Is", "==", "!=", "is not") -$value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value") \ No newline at end of file +$value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value") \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindRuleParserTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/FindRuleParserTests.cs index 64987c9..3ca9d3f 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/FindRuleParserTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindRuleParserTests.cs @@ -49,17 +49,17 @@ public void FindRuleExprParsingShouldBeEqualsCustomResult(string ruleStr, string Assert.NotNull(rule); Assert.Equal(_ruleStr, customResult.ToLower()); } - [Theory] - [InlineData("FindRule/NullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"")] + [InlineData("FindRule/NullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"", "$value$ In $value1$,\"$value1$\\.Value\",$value2$,\"$value2$\\.Value\"")] [InlineData("FindRule/AssignmentNullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"")] - public void FindRuleParsingFromFileShouldBeSuccess(string filePath, string customResult) + public void FindRuleParsingFromFileShouldBeSuccess(string filePath, params string[] customResult) { var ruleStr = File.ReadAllText(filePath); - var rule = StructuralSearch.ParseFindRule(ruleStr); - var _ruleStr = rule.ToString()?.ToLower(); - Assert.NotNull(rule); - Assert.Equal(_ruleStr, customResult.ToLower()); + var rules = ruleStr.Split(Constant.LineFeed) + .Select(StructuralSearch.ParseFindRule); + var rulesAsStr = rules.Select(x => x.ToString()).ToArray(); + + Assert.True(customResult.SequenceEqual(rulesAsStr)); } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateParserTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateParserTests.cs index 4abc086..e1a6e9b 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateParserTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateParserTests.cs @@ -12,7 +12,7 @@ public class FindTemplateTests [InlineData("FindTemplate/AssignmentNullUnionOperator.txt")] [InlineData("FindTemplate/NestedParenthesised.txt")] [InlineData("FindTemplate/TernaryOperator.txt")] - public void TemplateParsingShouldBeSuccess(string templatePath) + public void FindTemplateFromFileParsingShouldBeSuccess(string templatePath) { var findTemplate = File.ReadAllText(templatePath); var template = StructuralSearch.ParseFindTemplate(findTemplate); @@ -40,5 +40,19 @@ public void SourceParsingBeFindTemplateShouldBeSuccess(string templatePath, stri Assert.NotNull(findParser); Assert.Equal(match.Match.Lenght, source.Length); } + + [Theory] + [InlineData("( $var$")] + public void FindTemplateParsingShouldBeFail(string templateStr) + { + Assert.Throws(() => StructuralSearch.ParseFindTemplate(templateStr)); + } + + [Theory] + [InlineData("( $var$ )")] + public void FindTemplateParsingShouldBeSuccess(string templateStr) + { + var template = StructuralSearch.ParseFindTemplate(templateStr); + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceRuleParserTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceRuleParserTests.cs index 577c23b..0100154 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceRuleParserTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceRuleParserTests.cs @@ -9,6 +9,8 @@ public class ReplaceRuleParserTests [Theory] [InlineData("$var1$ equals $var2$ then $var1$ => \"test $var3$\"")] [InlineData("$var1$ equals \"\\$\" then $var1$ => \"\\$\",$var2$ => \"132\"")] + [InlineData("_ then $var1$ => \"test $var3$.Lenght\"")] + [InlineData("_ then $var1$ => \"\\$\",$var2$ => \"132\"")] [InlineData("Not $var1$ equals $var$.Lenght then $var1$ => $var$.Lenght")] [InlineData("Not $var1$ equals $var$.offset.Start then $var1$ => $var$.offset.Start")] [InlineData("$var1$ equals $var$.Lenght and Not $var1$ StartsWith \"123\" then $var1$ => $var$.offset.Start.Trim")] @@ -22,5 +24,24 @@ public void ReplaceRuleParsingShouldBeSuccess(string replaceRule) Assert.Equal(ruleStr, replaceRule.ToLower()); } + [Theory] + [InlineData("($var1$ equals $var2$) then $var1$ => \"test $var3$\"", "$var1$ equals $var2$ then $var1$ => \"test $var3$\"")] + public void ReplaceRuleShouldBeEqualsString(string replaceRule, string customResult) + { + var rule = StructuralSearch.ParseReplaceRule(replaceRule); + var ruleStr = rule.ToString().ToLower(); + Assert.NotNull(rule); + Assert.Equal(ruleStr, customResult.ToLower()); + } + + [Theory] + [InlineData("$var1$ equals $var2$ then $var1$ => (\"test $var3$\"")] + [InlineData("($var1$ equals $var2$ then $var1$ => \"test $var3$\"")] + [InlineData("$var1$ equals $var2$ then ($var1$) => \"test $var3$\"")] + public void ReplaceRuleParsingShouldBeFail(string replaceRuleStr) + { + Assert.Throws(() => StructuralSearch.ParseReplaceRule(replaceRuleStr)); + } + } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs index db25cb1..89d4fc7 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Pidgin; using SimpleStateMachine.StructuralSearch.Tests.Mock; using Xunit; @@ -9,10 +10,10 @@ namespace SimpleStateMachine.StructuralSearch.Tests public class ReplaceTemplateTests { [Theory] - [InlineData("ReplaceTemplate/NullUnionOperator.txt", 10)] - [InlineData("ReplaceTemplate/AssignmentNullUnionOperator.txt", 6)] - [InlineData("ReplaceTemplate/TernaryOperator.txt", 11)] - public void TemplateParsingShouldHaveStepCount(string templatePath, int stepsCount) + [InlineData("ReplaceTemplate/NullUnionOperator.txt", 6)] + [InlineData("ReplaceTemplate/AssignmentNullUnionOperator.txt", 4)] + [InlineData("ReplaceTemplate/TernaryOperator.txt", 7)] + public void ReplaceTemplateParsingShouldHaveStepCount(string templatePath, int stepsCount) { var replaceTemplate = File.ReadAllText(templatePath); var replaceBuilder = StructuralSearch.ParseReplaceTemplate(replaceTemplate); @@ -50,5 +51,27 @@ public void ReplaceBuildShouldBeSuccess(string templatePath, string resultPath, Assert.NotNull(replaceResult); Assert.Equal(replaceResult, result); } + + // TODO validation parenthesis for parameters + + [Theory] + [InlineData("test $var1$.Lenght")] + [InlineData("(test $var1$.Lenght)")] + [InlineData("test ($var1$.Lenght)")] + public void ReplaceTemplateParsingShouldBeSuccess(string templateStr) + { + var replaceBuilder = StructuralSearch.ParseReplaceTemplate(templateStr); + var replaceStr = replaceBuilder.ToString().ToLower(); + Assert.Equal(replaceStr, templateStr.ToLower()); + } + + [Theory] + [InlineData("(test $var1$.Lenght")] + [InlineData("test ($var1$.Lenght")] + [InlineData("test $var1$.Lenght)")] + public void ReplaceTemplateParsingShouldBeFail(string templateStr) + { + Assert.Throws(() => StructuralSearch.ParseReplaceTemplate(templateStr)); + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Constant.cs b/src/SimpleStateMachine.StructuralSearch/Constant.cs index 4466a87..153d3a8 100644 --- a/src/SimpleStateMachine.StructuralSearch/Constant.cs +++ b/src/SimpleStateMachine.StructuralSearch/Constant.cs @@ -1,4 +1,6 @@ -namespace SimpleStateMachine.StructuralSearch +using System.Linq; + +namespace SimpleStateMachine.StructuralSearch { public static partial class Constant { @@ -10,102 +12,107 @@ public static partial class Constant /// /// String: "Not" /// - public static readonly string Not ="Not"; + public const string Not ="Not"; /// /// String: "Then" /// - public static readonly string Then ="Then"; + public const string Then ="Then"; /// /// Parenthesis char: '(' /// - public static readonly char LeftParenthesis = '('; + public const char LeftParenthesis = '('; /// /// Parenthesis char: ')' /// - public static readonly char RightParenthesis = ')'; + public const char RightParenthesis = ')'; /// /// Parenthesis char: '[' /// - public static readonly char LeftSquareParenthesis = '['; + public const char LeftSquareParenthesis = '['; /// /// Parenthesis char: ']' /// - public static readonly char RightSquareParenthesis = ']'; + public const char RightSquareParenthesis = ']'; /// /// Parenthesis char: '{' /// - public static readonly char LeftCurlyParenthesis = '{'; + public const char LeftCurlyParenthesis = '{'; /// /// Parenthesis char: '}' /// - public static readonly char RightCurlyParenthesis = '}'; + public const char RightCurlyParenthesis = '}'; /// /// Char: '$' /// - public static readonly char PlaceholderSeparator = '$'; + public const char PlaceholderSeparator = '$'; /// /// Char: '\r' /// - public static readonly char CarriageReturn = '\r'; + public const char CarriageReturn = '\r'; /// /// Char: '\n' /// - public static readonly char LineFeed = '\n'; + public const char LineFeed = '\n'; /// /// Char: ' ' /// - public static readonly char Space = ' '; + public const char Space = ' '; /// /// Char: ',' /// - public static readonly char Comma = ','; + public const char Comma = ','; /// /// Char: '\'' /// - public static readonly char SingleQuotes = '\''; + public const char SingleQuotes = '\''; /// /// Char: '\"' /// - public static readonly char DoubleQuotes = '\"'; + public const char DoubleQuotes = '\"'; /// /// Char: '\"' /// - public static readonly char BackSlash = '\\'; + public const char BackSlash = '\\'; /// /// Char: '.' /// - public static readonly char Dote = '.'; + public const char Dote = '.'; /// /// Char: '=' /// - public static readonly char Equals = '='; + public const char Equals = '='; /// /// Char: '>' /// - public static readonly char More = '>'; + public const char More = '>'; + + /// + /// Char: '_' + /// + public const char Underscore = '_'; /// /// Char: ':' /// - public static readonly char Colon = ':'; + public const char Colon = ':'; /// /// String: "=>" @@ -131,5 +138,18 @@ public static partial class Constant /// Parenthesis chars: '(' and ')', '{ and '}', '{ and '}' /// public static readonly (char, char)[] AllParenthesised = { Parenthesis, SquareParenthesis, CurlyParenthesis }; + + /// + /// Parenthesis chars: '(' and ')', '{ and '}', '{ and '}' + /// + public static readonly char[] AllParenthesisArray = + { + LeftParenthesis, + RightParenthesis, + LeftSquareParenthesis, + RightSquareParenthesis, + LeftCurlyParenthesis, + RightCurlyParenthesis + }; } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Extensions/ArrayExpression.cs b/src/SimpleStateMachine.StructuralSearch/Extensions/ArrayExpression.cs new file mode 100644 index 0000000..256bed2 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Extensions/ArrayExpression.cs @@ -0,0 +1,13 @@ +using System.Linq; + +namespace SimpleStateMachine.StructuralSearch.Extensions; + +public static class ArrayExpression +{ + public static T[] Add(this T[] array, params T[] values) + { + var list = array.ToList(); + list.AddRange(values); + return list.ToArray(); + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Extensions/ParserExtensions.cs b/src/SimpleStateMachine.StructuralSearch/Extensions/ParserExtensions.cs index 4a46019..35e2f5d 100644 --- a/src/SimpleStateMachine.StructuralSearch/Extensions/ParserExtensions.cs +++ b/src/SimpleStateMachine.StructuralSearch/Extensions/ParserExtensions.cs @@ -113,5 +113,10 @@ public static Parser After(this Parser parse { return parserAfter.Then(parser, (u, t) => t); } + + public static Parser ParenthesisedOptional(this Parser parser, Func, Parser> custom) + { + return OneOf(CommonParser.Parenthesised(parser, custom).Try(), parser); + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs index e64b0d9..2640500 100644 --- a/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs @@ -91,11 +91,11 @@ public static Parser> BetweenOneOfChars(Func BetweenOneOf(Func> leftRight, - Parser expr, params (char, char)[] values) - { - return OneOf(values.Select(x => expr.Between(leftRight(x.Item1), leftRight(x.Item2)))); - } + // public static Parser BetweenOneOf(Func> leftRight, + // Parser expr, params (char, char)[] values) + // { + // return OneOf(values.Select(x => expr.Between(leftRight(x.Item1), leftRight(x.Item2)))); + // } public static Parser> BetweenOneOfChars(Func> leftRight, Parser expr, params (char, char)[] values) diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/SubRule.cs b/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/BinarySubRule.cs similarity index 89% rename from src/SimpleStateMachine.StructuralSearch/Rules/FindRule/SubRule.cs rename to src/SimpleStateMachine.StructuralSearch/Rules/FindRule/BinarySubRule.cs index f670c7d..e4d5f5e 100644 --- a/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/SubRule.cs +++ b/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/BinarySubRule.cs @@ -3,7 +3,7 @@ namespace SimpleStateMachine.StructuralSearch.Rules { - public class SubRule : IRule + public class BinarySubRule : IRule { public SubRuleType Type { get; } @@ -11,7 +11,7 @@ public class SubRule : IRule public IRuleParameter Right { get; } - public SubRule(SubRuleType type, IRuleParameter left, IRuleParameter right) + public BinarySubRule(SubRuleType type, IRuleParameter left, IRuleParameter right) { Type = type; Left = left; diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/EmptySubRule.cs b/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/EmptySubRule.cs new file mode 100644 index 0000000..143e65e --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Rules/FindRule/EmptySubRule.cs @@ -0,0 +1,14 @@ +namespace SimpleStateMachine.StructuralSearch.Rules; + +public class EmptySubRule : IRule +{ + public bool Execute() + { + return true; + } + + public override string ToString() + { + return $"{Constant.Underscore}"; + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/ParametersParser.cs b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/ParametersParser.cs deleted file mode 100644 index 82ca401..0000000 --- a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/ParametersParser.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; -using Pidgin; -using SimpleStateMachine.StructuralSearch.Extensions; -using SimpleStateMachine.StructuralSearch.Rules; - -namespace SimpleStateMachine.StructuralSearch -{ - public static class ParametersParser - { - public static readonly Parser PlaceholderParameter = - CommonTemplateParser.Placeholder - .Select(x => new PlaceholderParameter(x)) - .TrimStart() - .Try(); - - public static readonly Parser PlaceholderRuleParameter = - PlaceholderParameter - .As(); - - public static readonly Parser StringParameter = - CommonParser.Escaped(Constant.DoubleQuotes, Constant.PlaceholderSeparator) - .Or(Parser.AnyCharExcept(Constant.DoubleQuotes, Constant.PlaceholderSeparator)) - .AtLeastOnceString() - .Select(x => new StringParameter(x)) - .As() - .Try(); - - public static readonly Parser StringFormatParameter = - Parser.OneOf(StringParameter, PlaceholderPropertyParser.PlaceholderPropertyParameter, PlaceholderRuleParameter) - .AtLeastOnce() - .Between(CommonParser.DoubleQuotes) - .Select(parameters => new StringFormatParameter(parameters)) - .As() - .TrimStart() - .Try(); - - public static readonly Parser Parameter = - Parser.OneOf(PlaceholderPropertyParser.PlaceholderPropertyParameter, PlaceholderRuleParameter, StringFormatParameter) - .TrimStart() - .Try(); - - public static readonly Parser> Parameters = - Parameter.SeparatedAtLeastOnce(CommonParser.Comma); - - } -} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderPropertyParser.cs b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderPropertyParser.cs index 76e1c4a..7daafea 100644 --- a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderPropertyParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderPropertyParser.cs @@ -45,13 +45,19 @@ public static class PlaceholderPropertyParser .Select(property => new Func(placeholder => new PlaceholderLenghtParameter(placeholder, property))) .Try(); - - public static readonly Parser PlaceholderPropertyParameter = - CommonTemplateParser.Placeholder.Before(CommonParser.Dote) - .Select(name => new PlaceholderParameter(name)) - .Then(Parser.OneOf(Lenght, File, Column, Offset, Line), - (placeholder, func) => func(placeholder)) - .TrimStart() + + public static readonly Parser> PlaceholderPropertyParameter = + CommonParser.Dote.Then(Parser.OneOf(Lenght, File, Column, Offset, Line)).Optional() + .Select(property => new Func(placeholder => + property.HasValue ? property.Value(placeholder) : placeholder)) .Try(); + + // public static readonly Parser PlaceholderPropertyParameter = + // CommonTemplateParser.Placeholder.Before(CommonParser.Dote) + // .Select(name => new PlaceholderParameter(name)) + // .Then(Parser.OneOf(Lenght, File, Column, Offset, Line), + // (placeholder, func) => func(placeholder)) + // .TrimStart() + // .Try(); } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/StringParameter.cs b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/StringParameter.cs index 40f7bbb..b94bf9e 100644 --- a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/StringParameter.cs +++ b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/StringParameter.cs @@ -16,8 +16,7 @@ public string GetValue() public override string ToString() { - var value = EscapeHelper.EscapeChars(Value, c => $"{Constant.BackSlash}{c}", Constant.PlaceholderSeparator, - Constant.DoubleQuotes); + var value = EscapeHelper.EscapeChars(Value, c => $"{Constant.BackSlash}{c}", Constant.Parameter.Escape); return $"{value}"; } diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/CommonParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/CommonParser.cs index b809955..d7ec275 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/CommonParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/CommonParser.cs @@ -10,11 +10,14 @@ internal static readonly Parser Empty = Parsers.String(Constant.Empty, false); internal static readonly Parser AnyChar - = AnyCharExcept(Constant.FindTemplate.All()); + = AnyCharExcept(Constant.FindTemplate.All); internal static readonly Parser Space = Char(Constant.Space); + internal static readonly Parser EOF + = Parser.End; + internal static readonly Parser AnyString = AnyChar.AtLeastOnceString(); @@ -45,6 +48,9 @@ internal static readonly Parser SingleQuotes internal static readonly Parser Dote = Char(Constant.Dote); + + internal static readonly Parser Underscore + = Char(Constant.Underscore); internal static Parser Parenthesised(Parser parser, Func, Parser> custom) { diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindRulesParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindRulesParser.cs index bce825c..8ed2ab6 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindRulesParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindRulesParser.cs @@ -71,7 +71,7 @@ internal static readonly Parser> Not internal static IRule ParseTemplate(string str) { - return Expr.ParseOrThrow(str); + return Expr.Before(CommonParser.EOF).ParseOrThrow(str); } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs index d8f6bbb..c3c0b0b 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs @@ -17,7 +17,7 @@ static FindTemplateParser() .MergerMany(); TemplateParser = Parser.OneOf(Parenthesised, Token) - .AtLeastOnce() + .AtLeastOnceUntil(CommonParser.EOF) .MergerMany(); SeriesParser = TemplateParser.Select(parsers => new SeriesParser(parsers)); diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ParametersParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ParametersParser.cs new file mode 100644 index 0000000..bb1464b --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ParametersParser.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using Pidgin; +using SimpleStateMachine.StructuralSearch.Extensions; +using SimpleStateMachine.StructuralSearch.Rules; + +namespace SimpleStateMachine.StructuralSearch +{ + public static class ParametersParser + { + + static ParametersParser() + { + Parenthesised = Parsers.BetweenOneOfChars(Parser.Char, + Parser.Rec(() => Test), + Constant.AllParenthesised); + + Test = Parser.OneOf(Parenthesised, String); + + Str = Test.AsString() + .Select(x => new StringParameter(x)) + .As() + .Try(); + + + // Term = Parser.OneOf(Parenthesised, Token) + // .Many() + // .MergerMany(); + } + + public static readonly Parser> String = + CommonParser.Escaped(Constant.Parameter.Escape) + .Or(Parser.AnyCharExcept(Constant.Parameter.Excluded)) + .AtLeastOnce(); + + public static readonly Parser> Parenthesised; + + public static readonly Parser> Test; + + + + public static readonly Parser Str; + + + // .Select(x => new StringParameter(x)) + // .As() + // .Try(); + + public static readonly Parser PlaceholderParameter = + CommonTemplateParser.Placeholder + .Select(x => new PlaceholderParameter(x)) + .TrimStart() + .Try(); + + // public static readonly Parser PlaceholderRuleParameter = + // PlaceholderParameter + // .As(); + + + public static readonly Parser> ChangeParameter = + CommonParser.Dote.Then(Parser.CIEnum()) + .Optional() + .Select(changeType => new Func(placeholder => + changeType.HasValue ? new ChangeParameter(placeholder, changeType.Value) : placeholder)) + .Try(); + + public static readonly Parser PlaceholderOrPropertyRuleParameter = + PlaceholderParameter.Then(PlaceholderPropertyParser.PlaceholderPropertyParameter, + (placeholder, func) => func(placeholder)) + .Then(ChangeParameter, (parameter, func) => func(parameter)) + .Try(); + + public static readonly Parser StringParameter = + CommonParser.Escaped(Constant.Parameter.Escape) + .Or(Parser.AnyCharExcept(Constant.Parameter.Excluded)) + .AtLeastOnceString() + .Select(x => new StringParameter(x)) + .As() + .Try(); + + public static readonly Parser StringFormatParameter = + Parser.OneOf(PlaceholderOrPropertyRuleParameter, Str) + .AtLeastOnce() + .Between(CommonParser.DoubleQuotes) + .Select(parameters => new StringFormatParameter(parameters)) + .As() + .TrimStart() + .Try(); + + public static readonly Parser Parameter = + Parser.OneOf(StringFormatParameter, PlaceholderOrPropertyRuleParameter) + .TrimStart() + .Try(); + + public static readonly Parser> Parameters = + Parameter.SeparatedAtLeastOnce(CommonParser.Comma); + + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceRuleParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceRuleParser.cs index 1c8bf34..22cfcdd 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceRuleParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceRuleParser.cs @@ -1,4 +1,6 @@ -using Pidgin; +using System; +using System.Collections.Generic; +using Pidgin; using SimpleStateMachine.StructuralSearch.Extensions; using SimpleStateMachine.StructuralSearch.Rules; @@ -6,36 +8,35 @@ namespace SimpleStateMachine.StructuralSearch { public static class ReplaceRuleParser { - internal static readonly Parser ChangeParameter = - Parser.Map((parameter, changeType) => new ChangeParameter(parameter, changeType), - ParametersParser.Parameter.Before(CommonParser.Dote), - Parser.CIEnum()) - .As() - .Try() - .TrimStart(); - internal static readonly Parser Then = Parser.CIString(Constant.Then) .Try() .TrimStart(); internal static readonly Parser ReplaceSubRule = - Parser.Map((placeholder, parameter) => new ReplaceSubRule(placeholder, parameter), - ParametersParser.PlaceholderParameter.Before(CommonTemplateParser.Should.TrimStart()), - Parser.OneOf(ChangeParameter.Try(), ParametersParser.Parameter.Try())) + Parser.Map((placeholder, _, parameter) => new ReplaceSubRule(placeholder, parameter), + ParametersParser.PlaceholderParameter.TrimStart(), + CommonTemplateParser.Should.TrimStart(), + ParametersParser.Parameter) + .Try() + .TrimStart(); + + internal static readonly Parser EmptySubRule = + CommonParser.Underscore.ThenReturn(new EmptySubRule()) + .As() .Try() .TrimStart(); internal static readonly Parser ReplaceRule = Parser.Map((rule, subRules) => new ReplaceRule(rule, subRules), - FindRuleParser.Expr, + Parser.OneOf(EmptySubRule, FindRuleParser.Expr), Then.Then(ReplaceSubRule.SeparatedAtLeastOnce(CommonParser.Comma))) .Try() .TrimStart(); - + internal static ReplaceRule ParseTemplate(string str) { - return ReplaceRule.ParseOrThrow(str); + return ReplaceRule.Before(CommonParser.EOF).ParseOrThrow(str); } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceTemplateParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceTemplateParser.cs index 005d7ba..583eabc 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceTemplateParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/ReplaceTemplateParser.cs @@ -2,55 +2,73 @@ using Pidgin; using SimpleStateMachine.StructuralSearch.Extensions; using SimpleStateMachine.StructuralSearch.ReplaceTemplate; +using SimpleStateMachine.StructuralSearch.Rules; namespace SimpleStateMachine.StructuralSearch { internal class ReplaceTemplateParser { - static ReplaceTemplateParser() - { - Parenthesised = Parsers.BetweenOneOfChars(x=> ParserToReplace.Stringc(x), - Parser.Rec(() => Term), - Constant.AllParenthesised); - - Term = Parser.OneOf(Parenthesised, Token) - .Many() - .MergerMany(); - - TemplateParser = Parser.OneOf(Parenthesised, Token) - .AtLeastOnce() - .MergerMany(); - } - - internal static readonly Parser Empty = - ParserToReplace.ResultAsReplace(CommonParser.Empty); - - internal static readonly Parser AnyString = - ParserToReplace.ResultAsReplace(CommonParser.AnyString) + // static ReplaceTemplateParser() + // { + // Parenthesised = Parsers.BetweenOneOfChars(x=> ParserToReplace.Stringc(x), + // Parser.Rec(() => Term), + // Constant.AllParenthesised); + // + // Term = Parser.OneOf(Parenthesised, Token) + // .Many() + // .MergerMany(); + // + // TemplateParser = Parser.OneOf(Parenthesised, Token) + // .AtLeastOnceUntil(CommonParser.EOF) + // .MergerMany(); + // } + // + // internal static readonly Parser Empty = + // ParserToReplace.ResultAsReplace(CommonParser.Empty); + // + // internal static readonly Parser AnyString = + // ParserToReplace.ResultAsReplace(CommonParser.AnyString) + // .Try(); + // + // internal static readonly Parser WhiteSpaces = + // ParserToReplace.ResultAsReplace(CommonParser.WhiteSpaces) + // .Try(); + // + // internal static readonly Parser Placeholder = + // CommonTemplateParser.Placeholder.Select(name=> new PlaceholderReplace(name)) + // .As() + // .Try(); + // + // internal static readonly Parser> Token = + // Parser.OneOf(AnyString, Placeholder, WhiteSpaces) + // .AsMany(); + // + // internal static readonly Parser> Term; + // + // internal static readonly Parser> Parenthesised; + // + // internal static readonly Parser> TemplateParser; + // + // internal static IReplaceBuilder ParseTemplate(string str) + // { + // return TemplateParser + // .Select(steps => new ReplaceBuilder(steps)) + // .ParseOrThrow(str); + // } + + public static readonly Parser Parameter = + Parser.OneOf(ParametersParser.Str, + ParametersParser.PlaceholderOrPropertyRuleParameter) + .Then(ParametersParser.ChangeParameter, (parameter, func) => func(parameter)) .Try(); - internal static readonly Parser WhiteSpaces = - ParserToReplace.ResultAsReplace(CommonParser.WhiteSpaces) + public static readonly Parser> Parameters = + Parameter.AtLeastOnceUntil(CommonParser.EOF) .Try(); - - internal static readonly Parser Placeholder = - CommonTemplateParser.Placeholder.Select(name=> new PlaceholderReplace(name)) - .As() - .Try(); - - internal static readonly Parser> Token = - Parser.OneOf(AnyString, Placeholder, WhiteSpaces) - .AsMany(); - - internal static readonly Parser> Term; - - internal static readonly Parser> Parenthesised; - - private static readonly Parser> TemplateParser; - + internal static IReplaceBuilder ParseTemplate(string str) { - return TemplateParser + return Parameters .Select(steps => new ReplaceBuilder(steps)) .ParseOrThrow(str); } diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/SubRuleParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/SubRuleParser.cs index 1d24283..be94c6e 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/SubRuleParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/SubRuleParser.cs @@ -10,9 +10,9 @@ public static class SubRuleParser public static readonly Parser SubRuleType = Parser.CIEnum().TrimStart(); - public static Parser SubRule(IRuleParameter left, SubRuleType ruleType) => - ParametersParser.Parameter.Select(right => new SubRule(ruleType, left, right)) - .As() + public static Parser BinarySubRule(IRuleParameter left, SubRuleType ruleType) => + ParametersParser.Parameter.Select(right => new BinarySubRule(ruleType, left, right)) + .As() .Try(); public static readonly Parser PlaceholderType = @@ -25,13 +25,12 @@ public static Parser IsSubRule(IRuleParameter left, SubRuleType rul .Try(); public static Parser InSubRule(IRuleParameter left, SubRuleType ruleType) => - Parser.OneOf(ParametersParser.Parameters, - CommonParser.Parenthesised(ParametersParser.Parameters, x => x.Trim())) + ParametersParser.Parameters + .ParenthesisedOptional(x => x.Trim()) .Select(args => new InSubRule(left, args)) .As() .Try(); - - + public static readonly Parser OneOfSubRule = Parser.Map((left, ruleType) => (left, ruleType), ParametersParser.Parameter, SubRuleType) @@ -39,7 +38,7 @@ public static Parser InSubRule(IRuleParameter left, SubRuleType rul { Rules.SubRuleType.In => InSubRule(x.left, x.ruleType), Rules.SubRuleType.Is => IsSubRule(x.left, x.ruleType), - _ => SubRule(x.left, x.ruleType) + _ => BinarySubRule(x.left, x.ruleType) }); } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/FindTemplate/ConstantFindTemplate.cs b/src/SimpleStateMachine.StructuralSearch/Templates/FindTemplate/ConstantFindTemplate.cs index 19db4d3..af08b28 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/FindTemplate/ConstantFindTemplate.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/FindTemplate/ConstantFindTemplate.cs @@ -1,4 +1,5 @@ using System.Linq; +using SimpleStateMachine.StructuralSearch.Extensions; namespace SimpleStateMachine.StructuralSearch { @@ -6,28 +7,31 @@ public static partial class Constant { public static class FindTemplate { - public static char[] All() - { - var all = new char[]{ - LeftParenthesis, - RightParenthesis, - LeftSquareParenthesis, - RightSquareParenthesis, - LeftCurlyParenthesis, - RightCurlyParenthesis, - PlaceholderSeparator, - CarriageReturn, - LineFeed, - Space - }; + public static readonly char[] All = AllParenthesisArray.Add + ( + PlaceholderSeparator, + CarriageReturn, + LineFeed, + Space + ); - return all; - } - public static char[] AllExclude(params char[] excluded) { - return All().Where(x => !excluded.Contains(x)).ToArray(); + return All.Where(x => !excluded.Contains(x)).ToArray(); } } + + public static class Parameter + { + public static readonly char[] Escape = + { + DoubleQuotes, + PlaceholderSeparator, + Dote, + }; + + public static readonly char[] Excluded = AllParenthesisArray + .Add(Escape); + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs index ab1aa34..0a9fc50 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using SimpleStateMachine.StructuralSearch.Rules; namespace SimpleStateMachine.StructuralSearch.ReplaceTemplate { public interface IReplaceBuilder { - IEnumerable Steps { get; } + IEnumerable Steps { get; } string Build(IParsingContext context); } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs index 986c0c5..639bb12 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs @@ -20,5 +20,10 @@ public void SetContext(ref IParsingContext context) { _context = context; } + + public override string ToString() + { + return $"{Constant.PlaceholderSeparator}{Name}{Constant.PlaceholderSeparator}"; + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs index 81c0c35..4ebe621 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; using System.Text; +using SimpleStateMachine.StructuralSearch.Rules; namespace SimpleStateMachine.StructuralSearch.ReplaceTemplate { public class ReplaceBuilder : IReplaceBuilder { - public IEnumerable Steps { get; } + public IEnumerable Steps { get; } - public ReplaceBuilder(IEnumerable steps) + public ReplaceBuilder(IEnumerable steps) { Steps = steps; } @@ -29,5 +30,10 @@ public string Build(IParsingContext context) var result = stringBuilder.ToString(); return result; } + + public override string ToString() + { + return $"{string.Join(string.Empty, Steps)}"; + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/TokenReplace.cs b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/TokenReplace.cs index 6f8d247..8333b1b 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/TokenReplace.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/TokenReplace.cs @@ -12,5 +12,10 @@ public string GetValue() { return Token; } + + public override string ToString() + { + return $"{Token}"; + } } } \ No newline at end of file