diff --git a/src/SimpleStateMachine.StructuralSearch.Sandbox/Program.cs b/src/SimpleStateMachine.StructuralSearch.Sandbox/Program.cs index e80b601..bcffd39 100644 --- a/src/SimpleStateMachine.StructuralSearch.Sandbox/Program.cs +++ b/src/SimpleStateMachine.StructuralSearch.Sandbox/Program.cs @@ -1,9 +1,13 @@ using System; using System.Linq; +using System.Text.Json; using System.Text.RegularExpressions; using Pidgin; +using SimpleStateMachine.StructuralSearch.Configurations; using SimpleStateMachine.StructuralSearch.Extensions; using SimpleStateMachine.StructuralSearch.Rules; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; using static Pidgin.Parser; using String = System.String; diff --git a/src/SimpleStateMachine.StructuralSearch.Sandbox/SimpleStateMachine.StructuralSearch.Sandbox.csproj b/src/SimpleStateMachine.StructuralSearch.Sandbox/SimpleStateMachine.StructuralSearch.Sandbox.csproj index 8ea8467..34cf2f5 100644 --- a/src/SimpleStateMachine.StructuralSearch.Sandbox/SimpleStateMachine.StructuralSearch.Sandbox.csproj +++ b/src/SimpleStateMachine.StructuralSearch.Sandbox/SimpleStateMachine.StructuralSearch.Sandbox.csproj @@ -10,6 +10,7 @@ + diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml new file mode 100644 index 0000000..58583c7 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/FullConfig.yml @@ -0,0 +1,40 @@ +Configurations: + - FindTemplate: |- + if($var$ $sign$ null) + { + $var$ = $value$; + } + FindRules: + - $sign$ In ("Is", "==") + ReplaceTemplate: |- + $var$ ??= $value$; + ReplaceRules: + + + + - FindTemplate: |- + if($condition$) + return $value1$; + else + return $value2$; + FindRules: + ReplaceTemplate: |- + return $condition$? $value1$ : $value2$; + ReplaceRules: + + + + - FindTemplate: |- + if($value1$ $sign$ null) + { + $var$ = $value1$; + } + else + { + $var$ = $value2$; + } + FindRules: + - $sign$ In ("Is", "==") + ReplaceTemplate: |- + $var$ = $value1$ ?? $value2$; + ReplaceRules: \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml new file mode 100644 index 0000000..2c62d32 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFile/ShortConfig.yml @@ -0,0 +1,36 @@ +Configurations: + - FindTemplate: |- + if($var$ $sign$ null) + { + $var$ = $value$; + } + FindRules: + - $sign$ In ("Is", "==") + ReplaceTemplate: |- + $var$ ??= $value$; + + + + - FindTemplate: |- + if($condition$) + return $value1$; + else + return $value2$; + ReplaceTemplate: |- + return $condition$? $value1$ : $value2$; + + + + - FindTemplate: |- + if($value1$ $sign$ null) + { + $var$ = $value1$; + } + else + { + $var$ = $value2$; + } + FindRules: + - $sign$ In ("Is", "==") + ReplaceTemplate: |- + $var$ = $value1$ ?? $value2$; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFileTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFileTests.cs new file mode 100644 index 0000000..3059f3e --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ConfigurationFileTests.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Pidgin; +using SimpleStateMachine.StructuralSearch.Configurations; +using Xunit; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace SimpleStateMachine.StructuralSearch.Tests +{ + public class ConfigurationFileTests + { + [Theory] + [InlineData("ConfigurationFile/ShortConfig.yml")] + [InlineData("ConfigurationFile/FullConfig.yml")] + public void ConfigurationFileParsingShouldBeSuccess(string filePath) + { + var yml = File.ReadAllText(filePath); + var deserializer = new DeserializerBuilder() + .WithNamingConvention(PascalCaseNamingConvention.Instance) + .Build(); + + var cfg = deserializer.Deserialize(yml); + } + + // private ConfigurationsFile Mock() + // { + // var configurationFile = new ConfigurationsFile(); + // + // } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/IfValueIsNullFindRule.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/IfValueIsNullFindRule.txt new file mode 100644 index 0000000..7ef4c86 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindRule/IfValueIsNullFindRule.txt @@ -0,0 +1 @@ +$sign$ In ("Is", "==") \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseFindTemplate.txt similarity index 65% rename from src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseTemplate.txt rename to src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseFindTemplate.txt index da77bcc..2e6d69a 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseTemplate.txt +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfElseFindTemplate.txt @@ -1,4 +1,4 @@ -if($var1$ $sign$ $value1$) +if($var1$ $sign$ $some1$) { $var$ = $value1$; } diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfValueIsNullTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfValueIsNullFindTemplate.txt similarity index 100% rename from src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfValueIsNullTemplate.txt rename to src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/IfValueIsNullFindTemplate.txt diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/NestedParenthesisedTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/NestedParenthesisedFindTemplate.txt similarity index 100% rename from src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/NestedParenthesisedTemplate.txt rename to src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/NestedParenthesisedFindTemplate.txt diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/TernaryOperatorFindTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/TernaryOperatorFindTemplate.txt new file mode 100644 index 0000000..808476d --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplate/TernaryOperatorFindTemplate.txt @@ -0,0 +1,4 @@ +if($condition$) + return $value1$; +else + return $value2$; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateTests.cs index 48341c4..bc7e85f 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/FindTemplateTests.cs @@ -7,27 +7,30 @@ namespace SimpleStateMachine.StructuralSearch.Tests public class FindTemplateTests { [Theory] - [InlineData("FindTemplate/IfElseTemplate.txt")] - [InlineData("FindTemplate/IfValueIsNullTemplate.txt")] - [InlineData("FindTemplate/NestedParenthesisedTemplate.txt")] + [InlineData("FindTemplate/IfElseFindTemplate.txt")] + [InlineData("FindTemplate/IfValueIsNullFindTemplate.txt")] + [InlineData("FindTemplate/NestedParenthesisedFindTemplate.txt")] + [InlineData("FindTemplate/TernaryOperatorFindTemplate.txt")] public void TemplateParsingShouldBeSuccess(string templatePath) { var findTemplate = File.ReadAllText(templatePath); - var template = StructuralSearch.ParseFindTemplate(findTemplate); + var template = StructuralSearch.ParseFindTemplate(findTemplate, new ParsingContext()); Assert.NotNull(template); } [Theory] - [InlineData("FindTemplate/IfElseTemplate.txt", "Source/IfElseSource.txt")] - [InlineData("FindTemplate/IfValueIsNullTemplate.txt", "Source/IfValueIsNullSource.txt")] - [InlineData("FindTemplate/NestedParenthesisedTemplate.txt", "Source/NestedParenthesisedSource.txt")] + [InlineData("FindTemplate/IfElseFindTemplate.txt", "Source/IfElseSource.txt")] + [InlineData("FindTemplate/IfValueIsNullFindTemplate.txt", "Source/IfValueIsNullSource.txt")] + [InlineData("FindTemplate/NestedParenthesisedFindTemplate.txt", "Source/NestedParenthesisedSource.txt")] + [InlineData("FindTemplate/TernaryOperatorFindTemplate.txt", "Source/TernaryOperatorSource.txt")] public void SourceParsingBeFindTemplateShouldBeSuccess(string templatePath, string sourcePath) { var findTemplate = File.ReadAllText(templatePath); var source = File.ReadAllText(sourcePath); - var template = StructuralSearch.ParseFindTemplate(findTemplate); + var context = new ParsingContext(); + var template = StructuralSearch.ParseFindTemplate(findTemplate, context); var result = template.ParseOrThrow(source); Assert.NotNull(template); diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/Mock/EmptyParsingContext.cs b/src/SimpleStateMachine.StructuralSearch.Tests/Mock/EmptyParsingContext.cs new file mode 100644 index 0000000..bb60777 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/Mock/EmptyParsingContext.cs @@ -0,0 +1,20 @@ +namespace SimpleStateMachine.StructuralSearch.Tests.Mock +{ + public class EmptyParsingContext : IParsingContext + { + public bool TryGetPlaceholder(string name, out string value) + { + throw new System.NotImplementedException(); + } + + public void AddPlaceholder(string name, string value) + { + throw new System.NotImplementedException(); + } + + public string GetPlaceholder(string name) + { + return name; + } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/PlaceholderParserTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/PlaceholderParserTests.cs index cb4391b..891c18e 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/PlaceholderParserTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/PlaceholderParserTests.cs @@ -8,30 +8,32 @@ public class PlaceholderParserTests [Fact] public void FindTemplateShouldBeNotEmpty() { - Assert.Throws(() => StructuralSearch.ParseFindTemplate(string.Empty)); + Assert.Throws(() => StructuralSearch.ParseFindTemplate(string.Empty, new ParsingContext())); } [Theory] [InlineData("($test$)", "(value )", "value ")] [InlineData("($test$ )", "(value )", "value")] [InlineData("($test$)", "(value (test))", "value (test)")] + [InlineData("($test$)", "(value (test) )", "value (test) ")] public void TemplateParsingShouldBeSuccess(string template, string source, string result) { - var templateParser = StructuralSearch.ParseFindTemplate(template); + var context = new ParsingContext(); + var templateParser = StructuralSearch.ParseFindTemplate(template, context); var res = templateParser.ParseOrThrow(source); + var value = context.GetPlaceholder("test"); - // var templateStr = File.ReadAllText(templatePath); - // var template = StructuralSearch.ParseTemplate(templateStr); - // - // Assert.NotNull(template); + Assert.Equal(value, result); } [Theory] [InlineData("$var$;$var2$;", "test;;;test;;;", "value ")] public void TemplateParsingShouldBeSuccess2(string template, string source, string result) { - var templateParser = StructuralSearch.ParseFindTemplate(template); + var context = new ParsingContext(); + var templateParser = StructuralSearch.ParseFindTemplate(template, context); var res = templateParser.ParseOrThrow(source); + // var templateStr = File.ReadAllText(templatePath); // var template = StructuralSearch.ParseTemplate(templateStr); diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfElseReplaceResult.txt b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfElseReplaceResult.txt new file mode 100644 index 0000000..759b0d6 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfElseReplaceResult.txt @@ -0,0 +1 @@ +temp == 125 ? 12 : 15; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfValueIsNullReplaceResult.txt b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfValueIsNullReplaceResult.txt new file mode 100644 index 0000000..c479805 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/IfValueIsNullReplaceResult.txt @@ -0,0 +1 @@ +temp ??= 12; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/TernaryOperatorReplaceResult.txt b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/TernaryOperatorReplaceResult.txt new file mode 100644 index 0000000..14ef19f --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceResult/TernaryOperatorReplaceResult.txt @@ -0,0 +1 @@ +return temp == 125? 12 : 15; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/IfElseReplaceTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/IfElseReplaceTemplate.txt index 22b6f34..ae54928 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/IfElseReplaceTemplate.txt +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/IfElseReplaceTemplate.txt @@ -1 +1 @@ -$var1$ $sign$ $value1$ ? $value1$ : $value2$; \ No newline at end of file +$var1$ $sign$ $value1$ ? $value2$ : $value3$; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/TernaryOperatorReplaceTemplate.txt b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/TernaryOperatorReplaceTemplate.txt new file mode 100644 index 0000000..d8c217d --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplate/TernaryOperatorReplaceTemplate.txt @@ -0,0 +1 @@ +return $condition$? $value1$ : $value2$; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs index 3a681a7..ca7f668 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs +++ b/src/SimpleStateMachine.StructuralSearch.Tests/ReplaceTemplateTests.cs @@ -1,5 +1,7 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Linq; +using SimpleStateMachine.StructuralSearch.Tests.Mock; using Xunit; namespace SimpleStateMachine.StructuralSearch.Tests @@ -9,14 +11,44 @@ public class ReplaceTemplateTests [Theory] [InlineData("ReplaceTemplate/IfElseReplaceTemplate.txt", 14)] [InlineData("ReplaceTemplate/IfValueIsNullReplaceTemplate.txt", 6)] - public void TemplateParsingShouldBeSuccess(string templatePath, int stepsCount) + [InlineData("ReplaceTemplate/TernaryOperatorReplaceTemplate.txt", 11)] + public void TemplateParsingShouldHaveStepCount(string templatePath, int stepsCount) { var replaceTemplate = File.ReadAllText(templatePath); var replaceBuilder = StructuralSearch.ParseReplaceTemplate(replaceTemplate); - var result = replaceBuilder.Build(); - + var result = replaceBuilder.Build(new EmptyParsingContext()); + Assert.NotNull(replaceTemplate); Assert.Equal(replaceBuilder.Steps.Count(), stepsCount); } + + [Theory] + [InlineData("ReplaceTemplate/IfElseReplaceTemplate.txt", "ReplaceResult/IfElseReplaceResult.txt", + new[] { "var1", "sign", "value1", "value2", "value3" }, + new[] { "temp", "==", "125", "12", "15" })] + [InlineData("ReplaceTemplate/IfValueIsNullReplaceTemplate.txt", "ReplaceResult/IfValueIsNullReplaceResult.txt", + new[] { "var", "value" }, + new[] { "temp", "12" })] + [InlineData("ReplaceTemplate/TernaryOperatorReplaceTemplate.txt", "ReplaceResult/TernaryOperatorReplaceResult.txt", + new[] { "condition", "value1", "value2" }, + new[] { "temp == 125", "12", "15" })] + public void ReplaceBuildShouldBeSuccess(string templatePath, string resultPath, string[] keys, string[] values) + { + var replaceTemplate = File.ReadAllText(templatePath); + var replaceResult = File.ReadAllText(resultPath); + var replaceBuilder = StructuralSearch.ParseReplaceTemplate(replaceTemplate); + + var parsingContext = new ParsingContext(); + for (int i = 0; i < keys.Length; i++) + { + parsingContext.AddPlaceholder(keys[i], values[i]); + } + + var result = replaceBuilder.Build(parsingContext); + + Assert.NotNull(replaceTemplate); + Assert.NotNull(replaceResult); + Assert.Equal(replaceResult, result); + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/SimpleStateMachine.StructuralSearch.Tests.csproj b/src/SimpleStateMachine.StructuralSearch.Tests/SimpleStateMachine.StructuralSearch.Tests.csproj index 33c287e..16ce3e9 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/SimpleStateMachine.StructuralSearch.Tests.csproj +++ b/src/SimpleStateMachine.StructuralSearch.Tests/SimpleStateMachine.StructuralSearch.Tests.csproj @@ -18,6 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + @@ -34,6 +35,16 @@ Always + + Always + + + Always + + + + + diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/Source/IfElseSource.txt b/src/SimpleStateMachine.StructuralSearch.Tests/Source/IfElseSource.txt index 659fc58..eca8909 100644 --- a/src/SimpleStateMachine.StructuralSearch.Tests/Source/IfElseSource.txt +++ b/src/SimpleStateMachine.StructuralSearch.Tests/Source/IfElseSource.txt @@ -1,4 +1,4 @@ -if(temp = 125) +if(temp == 125) { test = 12; } diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/Source/TernaryOperatorSource.txt b/src/SimpleStateMachine.StructuralSearch.Tests/Source/TernaryOperatorSource.txt new file mode 100644 index 0000000..a6fa515 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/Source/TernaryOperatorSource.txt @@ -0,0 +1,4 @@ +if(temp == 125) + return 12; +else + return 15; \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch.Tests/Test.cs b/src/SimpleStateMachine.StructuralSearch.Tests/Test.cs new file mode 100644 index 0000000..cf92237 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch.Tests/Test.cs @@ -0,0 +1,13 @@ +using YamlDotNet.Serialization; +using System.Text.RegularExpressions; + +namespace SimpleStateMachine.StructuralSearch.Tests +{ + public class Test: INamingConvention + { + public string Apply(string value) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Configurations/Configuration.cs b/src/SimpleStateMachine.StructuralSearch/Configurations/Configuration.cs new file mode 100644 index 0000000..f44e82c --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Configurations/Configuration.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace SimpleStateMachine.StructuralSearch.Configurations +{ + public class Configuration + { + public string FindTemplate { get; set; } + + public List FindRules { get; set; } + + public string ReplaceTemplate { get; set; } + + public List ReplaceRules { get; set; } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Configurations/ConfigurationsFile.cs b/src/SimpleStateMachine.StructuralSearch/Configurations/ConfigurationsFile.cs new file mode 100644 index 0000000..b6afac7 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Configurations/ConfigurationsFile.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace SimpleStateMachine.StructuralSearch.Configurations +{ + public class ConfigurationsFile + { + public List Configurations { get; set; } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Extensions/SourceMatchManyParserExtensions.cs b/src/SimpleStateMachine.StructuralSearch/Extensions/SourceMatchManyParserExtensions.cs index f8c8374..3e13a28 100644 --- a/src/SimpleStateMachine.StructuralSearch/Extensions/SourceMatchManyParserExtensions.cs +++ b/src/SimpleStateMachine.StructuralSearch/Extensions/SourceMatchManyParserExtensions.cs @@ -9,13 +9,13 @@ public static class SourceMatchParserExtensions // { // return parsers.Select(x => Parsers.Series(x, getResult)); // } - public static Parser> JoinResults(this Parser>> parsers) + public static Parser> JoinResults(this Parser>> parsers, IParsingContext context) { - return parsers.Select(x => Parsers.Series(x, y => string.Join(string.Empty, y))); + return parsers.Select(x => Parsers.Series(context, x, y => string.Join(string.Empty, y))); } - public static Parser> JoinResults(this Parser>> parsers) + public static Parser> JoinResults(this Parser>> parsers, IParsingContext context) { - return parsers.Select(x => Parsers.Series(x, y => y.Concatenate())); + return parsers.Select(x => Parsers.Series(context, x, y => y.Concatenate())); } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/IParsingContext.cs b/src/SimpleStateMachine.StructuralSearch/IParsingContext.cs new file mode 100644 index 0000000..69e0ee0 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/IParsingContext.cs @@ -0,0 +1,11 @@ +namespace SimpleStateMachine.StructuralSearch +{ + public interface IParsingContext + { + bool TryGetPlaceholder(string name, out string value); + + void AddPlaceholder(string name, string value); + + string GetPlaceholder(string name); + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/IContextDependent.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/IContextDependent.cs new file mode 100644 index 0000000..9ca7b95 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/IContextDependent.cs @@ -0,0 +1,7 @@ +namespace SimpleStateMachine.StructuralSearch +{ + public interface IContextDependent + { + void SetContext(IParsingContext context); + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/LookaheadParser.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/LookaheadParser.cs index 6ad42ac..de0854d 100644 --- a/src/SimpleStateMachine.StructuralSearch/Parsers/LookaheadParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/LookaheadParser.cs @@ -1,25 +1,24 @@ -using System; +using System.Diagnostics.CodeAnalysis; using Pidgin; namespace SimpleStateMachine.StructuralSearch { - public abstract class LookaheadParser : Parser + internal sealed class LookaheadParser : Parser { - private Parser _parser { get; set; } + private readonly Parser _parser; - public abstract Parser BuildParser(Func?> next, - Func?> nextNext); - - public void Lookahead(Func?> next, Func?> nextNext) - { - _parser = BuildParser(next, nextNext); - } - - public override bool TryParse(ref ParseState state, ref PooledList> expected, - out T result) + public LookaheadParser(Parser parser) => this._parser = parser; + + public override bool TryParse(ref ParseState state, ref PooledList> expecteds, out T result) { - var res = _parser.TryParse(ref state, ref expected, out result); - return res; + state.PushBookmark(); + if (this._parser.TryParse(ref state, ref expecteds, out result)) + { + state.Rewind(); + return true; + } + state.PopBookmark(); + return false; } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/ParserWithLookahead.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/ParserWithLookahead.cs new file mode 100644 index 0000000..187e6e9 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/ParserWithLookahead.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Pidgin; + +namespace SimpleStateMachine.StructuralSearch +{ + public abstract class ParserWithLookahead : Parser + { + private Func> _parser { get; set; } + + public Func>> OnLookahead { get; set; } + + public abstract Parser BuildParser(Func?> next, + Func?> nextNext); + + public void Lookahead(Func?> next, Func?> nextNext) + { + // lazy initialization + _parser = () => BuildParser(next, nextNext); + } + + public override bool TryParse(ref ParseState state, ref PooledList> expected, + out T result) + { + var res = _parser().TryParse(ref state, ref expected, out result); + return res; + } + } + + public class LookaheadResult + { + public LookaheadResult(Parser parser, T result, int tokensCount) + { + Parser = parser; + Result = result; + TokensCount = tokensCount; + } + + public T Result { get; } + public int TokensCount { get; } + public Parser Parser; + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs index a8acdd5..7428beb 100644 --- a/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/Parsers.cs @@ -78,7 +78,7 @@ public static Parser> MapToMany(Parser Series(IEnumerable> parsers, + public static Parser Series(IParsingContext context, IEnumerable> parsers, Func, R> func) { if (parsers == null) @@ -86,7 +86,7 @@ public static Parser Series(IEnumerable(parsers, func); + return new SeriesParser(context, parsers, func); } public static Parser> BetweenChars(char left, char right, @@ -134,5 +134,10 @@ public static Parser EnumValue(TEnum value, bool ignoreCase { return Parsers.String(value.ToString(), ignoreCase).AsEnum(ignoreCase); } + + public static Parser Lookahead(Parser parser) => + parser != null ? (Parser) + new LookaheadParser(parser) + : throw new ArgumentNullException(nameof (parser)); } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Parsers/PlaceholderParser.cs b/src/SimpleStateMachine.StructuralSearch/Parsers/PlaceholderParser.cs index c1d1517..83a2d09 100644 --- a/src/SimpleStateMachine.StructuralSearch/Parsers/PlaceholderParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/Parsers/PlaceholderParser.cs @@ -1,56 +1,78 @@ using System; +using System.Collections.Generic; using Pidgin; using SimpleStateMachine.StructuralSearch.Extensions; namespace SimpleStateMachine.StructuralSearch { - public class PlaceholderParser : LookaheadParser + public class PlaceholderParser : ParserWithLookahead, IContextDependent { - public string Name { get; } - - public string Value { get; } + private IParsingContext _context; + public PlaceholderParser(string name) { Name = name; } - + + public string Name { get; } + public override Parser BuildParser(Func> next, Func> nextNext) { var _next = next(); var _nextNext = nextNext() ?? Parser.End.ThenReturn(string.Empty); - var _lookahead = Parser.Lookahead(_next.Then(_nextNext).Try()); - - Parser lookahead = new DebugParser(_lookahead); + var lookahead = Parsers.Lookahead(_next.Then(_nextNext, (s1, s2) => + { + OnLookahead = () => new List> + { + new(_next, s1, s1.Length), + new(_nextNext, s2, s2.Length), + }; + return Unit.Value; + }).Try()); + var anyString = CommonTemplateParser.AnyCharWithPlshd .AtLeastOnceAsStringUntil(lookahead); - - var simpleString = CommonTemplateParser.StringWithPlshd.Labelled("simpleString"); + + var simpleString = CommonTemplateParser.StringWithPlshd; var token = Parser.OneOf(simpleString, CommonParser.WhiteSpaces).Try(); Parser term = null; var parenthesised = Parsers.BetweenOneOfChars(x => Parsers.Stringc(x), expr: Parser.Rec(() => term), Constant.AllParenthesised).JoinToString(); - + term = Parser.OneOf(parenthesised, token).Many().JoinToString(); - + //parenthesised and tokens and whiteSpaces var prdsAndTokens = Parser.OneOf(parenthesised, token) .Until(lookahead) .JoinToString() .Try(); - + var parser = prdsAndTokens.Or(anyString); return parser; } - + public override bool TryParse(ref ParseState state, ref PooledList> expected, out string result) { - var res = base.TryParse(ref state, ref expected, out result); + bool res; + + // No use look-ahead if placeholder is already defined + if (_context.TryGetPlaceholder(Name, out var value)) + { + res = Parser.String(value).TryParse(ref state, ref expected, out result); + } + else + { + res = base.TryParse(ref state, ref expected, out result); + if (res) + _context.AddPlaceholder(Name, result); + } + return res; - } + } // internal Parser GetParser() @@ -80,5 +102,9 @@ public override bool TryParse(ref ParseState state, ref PooledList: Parser { private readonly Func, R> _getResult; - private readonly IEnumerable> parsers; - - public SeriesParser(IEnumerable> parsers, Func, R> getResult) + private readonly IEnumerable> _parsers; + private readonly IParsingContext _context; + private bool _initialized = false; + public SeriesParser(IParsingContext context, IEnumerable> parsers, Func, R> getResult) { - this._getResult = getResult; - this.parsers = parsers; + _getResult = getResult; + _parsers = parsers; + _context = context; } - + public override bool TryParse(ref ParseState state, ref PooledList> expecteds, out R result) { + Fill(); var results = new List(); - var count = parsers.Count(); + var count = _parsers.Count(); - for (var i = count-1; i >= 0 ; i--) + for (int i = 0; i < _parsers.Count(); i++) { - if (parsers.ElementAt(i) is LookaheadParser lookaheadParser) - { - var number = i; - lookaheadParser.Lookahead(() => parsers.ElementAtOrDefault(number + 1), () => - parsers.ElementAtOrDefault(number + 2)); - } - } - - for (int i = 0; i < parsers.Count(); i++) - { - var parser = parsers.ElementAt(i); + var parser = _parsers.ElementAt(i); if (!parser.TryParse(ref state, ref expecteds, out var _result)) { result = default (R); return false; } - - Console.WriteLine($"R: {_result.ToString()}"); results.Add(_result); + SkipLookedParsers(parser, ref state); + + void SkipLookedParsers(Parser parser, ref ParseState state) + { + if (parser is not ParserWithLookahead lookaheadParser || lookaheadParser is { OnLookahead: null }) + return; + + var lookaheadResults = lookaheadParser.OnLookahead.Invoke(); + + foreach (var result in lookaheadResults) + { + results.Add(result.Result); + state.Advance(result.TokensCount); + i++; + } + + //recursion + foreach (var result in lookaheadResults) + { + SkipLookedParsers(result.Parser, ref state); + } + } } result = _getResult(results); return true; } + + + private void Fill() + { + if(_initialized) + return; + + var count = _parsers.Count(); + + for (var i = count-1; i >= 0 ; i--) + { + var parser = _parsers.ElementAt(i); + if (parser is ParserWithLookahead lookaheadParser) + { + var number = i; + lookaheadParser.Lookahead(() => _parsers.ElementAtOrDefault(number + 1), () => + _parsers.ElementAtOrDefault(number + 2)); + } + + if (parser is IContextDependent element) + { + element.SetContext(_context); + } + } + + _initialized = true; + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/ParsingContext.cs b/src/SimpleStateMachine.StructuralSearch/ParsingContext.cs new file mode 100644 index 0000000..0465cd5 --- /dev/null +++ b/src/SimpleStateMachine.StructuralSearch/ParsingContext.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace SimpleStateMachine.StructuralSearch +{ + public class ParsingContext : IParsingContext + { + public Dictionary Placeholders { get; } = new(); + + public bool TryGetPlaceholder(string name, out string value) + { + return Placeholders.TryGetValue(name, out value); + } + + public void AddPlaceholder(string name, string value) + { + Placeholders[name] = value; + } + + public string GetPlaceholder(string name) + { + return Placeholders[name]; + } + } +} \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Placeholder.cs b/src/SimpleStateMachine.StructuralSearch/Placeholder.cs index 647b319..82d6405 100644 --- a/src/SimpleStateMachine.StructuralSearch/Placeholder.cs +++ b/src/SimpleStateMachine.StructuralSearch/Placeholder.cs @@ -1,17 +1,17 @@ namespace SimpleStateMachine.StructuralSearch { - public class Placeholder - { - public static Placeholder Not => null; - private PlaceholdersMaster _master; - public Placeholder(PlaceholdersMaster master, string name, SourceMatch match) - { - _master = master; - Name = name; - Match = match; - } - - public string Name { get; } - public SourceMatch Match { get; } - } + // public class Placeholder + // { + // public static Placeholder Not => null; + // private PlaceholdersMaster _master; + // public Placeholder(PlaceholdersMaster master, string name, SourceMatch match) + // { + // _master = master; + // Name = name; + // Match = match; + // } + // + // public string Name { get; } + // public SourceMatch Match { get; } + // } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderParameter.cs b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderParameter.cs index 2abf798..eea3068 100644 --- a/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderParameter.cs +++ b/src/SimpleStateMachine.StructuralSearch/Rules/Parameters/PlaceholderParameter.cs @@ -1,22 +1,29 @@ namespace SimpleStateMachine.StructuralSearch.Rules { - public class PlaceholderParameter : IRuleParameter + public class PlaceholderParameter : IRuleParameter, IContextDependent { - public string Name { get; } + private IParsingContext _context; public PlaceholderParameter(string name) { Name = name; } + public string Name { get; } + public string GetValue() { - throw new System.NotImplementedException(); + return _context.GetPlaceholder(Name); } public override string ToString() { return $"{Constant.PlaceholderSeparator}{Name}{Constant.PlaceholderSeparator}"; - } + } + + public void SetContext(IParsingContext context) + { + _context = context; + } } } \ No newline at end of file diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs index 3505eae..ae54714 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/FindTemplateParser.cs @@ -18,8 +18,7 @@ static FindTemplateParser() TemplateParser = Parser.OneOf(Parenthesised, Token) .AtLeastOnce() - .MergerMany() - .JoinResults(); + .MergerMany(); } internal static readonly Parser>> Empty = @@ -47,11 +46,11 @@ static FindTemplateParser() internal static readonly Parser>> Parenthesised; - private static readonly Parser> TemplateParser; + private static readonly Parser>> TemplateParser; - internal static Parser ParseTemplate(string str) + internal static Parser ParseTemplate(string str, IParsingContext context) { - return TemplateParser.ParseOrThrow(str).AsMatch(); + return TemplateParser.JoinResults(context).ParseOrThrow(str).AsMatch(); } diff --git a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/StructuralSearch.cs b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/StructuralSearch.cs index 8d3cafa..2febae4 100644 --- a/src/SimpleStateMachine.StructuralSearch/StructuralSearch/StructuralSearch.cs +++ b/src/SimpleStateMachine.StructuralSearch/StructuralSearch/StructuralSearch.cs @@ -6,8 +6,8 @@ namespace SimpleStateMachine.StructuralSearch { public static class StructuralSearch { - public static Parser ParseFindTemplate(string template) - => FindTemplateParser.ParseTemplate(template); + public static Parser ParseFindTemplate(string template, IParsingContext context) + => FindTemplateParser.ParseTemplate(template, context); public static IReplaceBuilder ParseReplaceTemplate(string template) => ReplaceTemplateParser.ParseTemplate(template); diff --git a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs index 8fd6460..ab1aa34 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/IReplaceBuilder.cs @@ -5,6 +5,6 @@ namespace SimpleStateMachine.StructuralSearch.ReplaceTemplate public interface IReplaceBuilder { IEnumerable Steps { get; } - string Build(); + 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 43fa400..840d21a 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/PlaceholderReplace.cs @@ -1,17 +1,24 @@ namespace SimpleStateMachine.StructuralSearch.ReplaceTemplate { - public class PlaceholderReplace:IReplaceStep + public class PlaceholderReplace : IReplaceStep, IContextDependent { - public string Name { get; } + private IParsingContext _context; + public string Name { get; } + public PlaceholderReplace(string name) { Name = name; } - + public string GetValue() { - return Name; + return _context.GetPlaceholder(Name); + } + + public void SetContext(IParsingContext context) + { + _context = context; } } } \ 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 50f9a88..bf06d24 100644 --- a/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs +++ b/src/SimpleStateMachine.StructuralSearch/Templates/ReplaceTemplate/ReplaceBuilder.cs @@ -12,12 +12,17 @@ public ReplaceBuilder(IEnumerable steps) Steps = steps; } - public string Build() + public string Build(IParsingContext context) { StringBuilder stringBuilder = new StringBuilder(); - + foreach (var step in Steps) { + if (step is IContextDependent contextDependentStep) + { + contextDependentStep.SetContext(context); + } + stringBuilder.Append(step.GetValue()); }