public string Generate(MatcherEngineGenerator generator) { string version = AssemblyName.GetAssemblyName(GetType().Assembly.Location).Version.ToString(); return($@" /* Generated by Synfron.Staxe.Matcher v{version}*/ using Synfron.Staxe.Matcher.Data; using System.Collections.Generic; using System; using System.Linq; using Synfron.Staxe.Matcher.Input; {(generator.LanguageMatcher.LogMatches ? "using System.Text;" : null)} namespace Synfron.Staxe.Matcher {{ public class {GetSafeMethodName(Name)}MatchEngine : AbstractLanguageMatchEngine {{ {GenerateMatch(generator)} <<Generated Methods>> }} }}"); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchWholeWord{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ if (startOffset - 1 >= 0 && char.IsLetterOrDigit(text[startOffset - 1])) {{ return (false, 0); }} (bool success, int offset) = {string.Format(_subPattern.Generate(generator), "text", "startOffset")}; int next = startOffset + offset; if (success && next < text.Length && char.IsLetterOrDigit(text[next])) {{ return (false, 0); }} return (success, offset); }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchInsensitiveLiteral{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ string literal = {$"\"{_literal.Replace(@"\", @"\\").Replace(@"""", @"\""").Replace("\n", @"\n").Replace("\t", @"\t")}\""}; int length = literal.Length; if (startOffset + length > text.Length) {{ return (false, 0); }} for (int i = 0; i < length; i++) {{ if (char.ToLowerInvariant(text[i + startOffset]) != char.ToLowerInvariant(literal[i])) {{ return (false, 0); }} }} return (true, length); }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchGroup{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); int numPatterns = _subPatterns.Count; string[] parts = new string[numPatterns]; for (int i = 0; i < numPatterns; i++) { parts[i] = $@" (success, subOffset) = {string.Format(_subPatterns[i].Generate(generator), "text", "offset")}; if (!success) {{ return (false, 0); }} offset += subOffset;"; } string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ int offset = startOffset; bool success; int subOffset; {string.Join("\n", parts)} return (true, offset - startOffset); }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchCountBounds{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ int offset = startOffset; bool subSuccess = true; int subOffset; int matches = 0; for (; matches < {_upperBounds} && subSuccess; matches++) {{ (subSuccess, subOffset) = {string.Format(_subPattern.Generate(generator), "text", "offset")}; offset += subOffset; }} bool success = subSuccess || matches >= {_lowerBounds}; return success ? (true, offset - startOffset) : (false, 0); }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchOneOrMore{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ int offset = startOffset; bool subSuccess = true; bool success = false; int subOffset; while (subSuccess) {{ (subSuccess, subOffset) = {string.Format(_subPattern.Generate(generator), "text", "offset")}; offset += subOffset; success |= subSuccess; }} return success ? (true, offset - startOffset) : (false, 0); }}"; method = generator.Add(method, methodName, code); } return(method); }
private string GenerateMatchPartByTextMatcher(MatcherEngineGenerator generator, PatternMatcher matcher) { string methodName = $"MatchPartByTextMatcher{GetSafeMethodName(matcher.Name)}"; string method = $"{methodName}(ref state, matchData)"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private bool {methodName}(ref State state, FragmentMatchData matchData) {{ {(generator.LanguageMatcher.LogMatches ? $@"int currentId = ++state.Id; state.MatchLogBuilder.AppendLine($""{{new String('\t', currentId)}} {{state.CurrentIndex}}. Try: {HttpUtility.JavaScriptStringEncode(matcher.Name)}"");" : null)} StringMatchData partMatchData; bool success = {string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, matcher), "partMatchData", "true", "false")}; if (success) {{ matchData.Parts.Add(partMatchData); {(generator.LanguageMatcher.LogMatches ? $@"state.MatchLogBuilder.AppendLine($""{{new String('\t', state.Id + 1)}} {{state.CurrentIndex}}. Matched: {{partMatchData.Text}}"");" : null)} }} {(generator.LanguageMatcher.LogMatches ? $@"state.MatchLogBuilder.AppendLine($""{{new String('\t', currentId)}} {{state.CurrentIndex}}. {{(success ? ""Passed"" : ""Failed"")}}: {HttpUtility.JavaScriptStringEncode(matcher.Name)}""); state.Id = currentId - 1;" : null)} return success; }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { if (_patternMatcher == null) { _patternMatcher = PatternReader.Parse(_pattern); } return _patternMatcher.Generate(generator); }
internal override string Generate(MatcherEngineGenerator generator) { return($@"(() => {{ Regex regex = new Regex({regex.ToString()}); Match match = regex.Match({{0}}, {{1}}); return (match?.Value, match?.Length ?? 0); }})()"); }
private string GenerateMatchFragmentParts(MatcherEngineGenerator generator) { switch (PartsMatchMode) { case MatchMode.Ordered: return(GenerateMatchFragmentPartsOrderedMode(generator)); case MatchMode.One: return(GenerateMatchFragmentPartsOneMode(generator)); case MatchMode.Multiple: default: return(GenerateMatchFragmentPartsMultipleMode(generator)); } }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchNot{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ return text.Length > startOffset && !{string.Format(_subPattern.Generate(generator), "text", "startOffset")}.success ? (true, 0) : (false, 0); }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchCharBounds{_id}"; string method = $"{methodName}({{0}}, {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private (bool success, int offset) {methodName}(string text, int startOffset) {{ int charVal = text[startOffset]; return ({(int)_lowerBounds} <= charVal && {(int)_upperBounds} >= charVal) ? (true, 1) : (false, 0); }}"; method = generator.Add(method, methodName, code); } return(method); }
private string GenerateMatchFragmentBounds(MatcherEngineGenerator generator, PatternMatcher matcher) { string methodName = $"MatchFragmentBounds{GetSafeMethodName(matcher.Name)}"; string method = $"{methodName}(ref state, {{0}}, out {{1}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private bool {methodName}(ref State state, bool readOnly, out StringMatchData matchData) {{ bool success = {string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, matcher), "matchData", "true", "readOnly")}; if ({(!Negate ? "!" : null)}success) {{ state.FailureIndex = Math.Max(state.FailureIndex ?? 0, state.CurrentIndex); }} {(generator.LanguageMatcher.LogMatches ? $@"state.MatchLogBuilder.AppendLine($""{{new String('\t', state.Id + 1)}} {{state.CurrentIndex}}. {{(success ? ""Passed"" : ""Failed"")}} Bounds: {{""{HttpUtility.JavaScriptStringEncode(matcher.ToString())}""}}"");" : null)} return success; }}"; method = generator.Add(method, methodName, code); } return(method); }
private string GenerateMatchFragmentPartsOneMode(MatcherEngineGenerator generator) { string methodName = $"MatchFragmentPartsOneMode{GetSafeMethodName(Name)}"; string method = $"{methodName}(ref state, partMatcherData)"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private bool {methodName}(ref State state, FragmentMatchData matchData) {{ bool success = false; int matchCount = 0; {(PartsPadding != null ? $"{string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false")};" : null)} {(Parts.Count > 0 ? $@" success = {string.Join(" || ", Parts.Select(part => GenerateMatchFragmentPart(generator, part)))}; if (success) {{ matchCount++; }}" : null)} {(PartsPadding != null ? $@"if (success) {{ {string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false")}; }}" : null)} success = {((MinMatchedParts ?? 1) <= 0).ToString().ToLower()} || matchCount > 0; if ({(!Negate ? "!" : null)}success) {{ state.FailureIndex = Math.Max(state.FailureIndex ?? 0, state.CurrentIndex); }} return success; }}"; method = generator.Add(method, methodName, code); } return(method); }
public string Generate(MatcherEngineGenerator generator) { string methodName = $"MatchFragment{GetSafeMethodName(Name)}"; string method = $"{methodName}(ref state, matchData)"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private bool {methodName}(ref State state, FragmentMatchData matchData) {{ {(generator.LanguageMatcher.LogMatches ? $@"int currentId = ++state.Id; state.MatchLogBuilder.AppendLine($""{{new String('\t', currentId)}} {{state.CurrentIndex}}. Try: {GetEscapedName()}"");" : null)} bool success = false; FragmentMatchData partMatcherData = null; {(Cacheable ? $@"if (!state.MatchCache.TryGetValue(new ValueTuple<string, int>(""{GetEscapedName()}"", state.CurrentIndex), out partMatcherData)) {{" : null)} int startIndex = state.CurrentIndex; int distinctIndex = state.DistinctIndex; partMatcherData = new FragmentMatchData {{ Name = ""{GetEscapedName()}"", StartIndex = state.CurrentIndex{(ExpressionOrder != null ? $@", ExpressionOrder = {ExpressionOrder}" : null)} }}; {(Start != null ? $"StringMatchData startMatchData;" : null)} {(End != null ? $"StringMatchData endMatchData;" : null)} success = ({(Start != null ? $"{string.Format(GenerateMatchFragmentBounds(generator, Start), DiscardBounds.ToString().ToLower(), "startMatchData")} && " : null)}{GenerateMatchFragmentParts(generator)}{(End != null ? $" && {string.Format(GenerateMatchFragmentBounds(generator, End), DiscardBounds.ToString().ToLower(), "endMatchData")}" : null)}); if (success) {{ {(!Negate ? $@"partMatcherData.Length = state.CurrentIndex - partMatcherData.StartIndex; partMatcherData.EndDistinctIndex = state.DistinctIndex;" : null)} {(Cacheable ? $@"state.MatchCache[new ValueTuple<string, int>(""{GetEscapedName()}"", startIndex)] = partMatcherData;" : null)} {(!IsNoise && ExpressionMode != ExpressionMode.None && !Negate ? $"ConvertToExpressionTree(partMatcherData, ExpressionMode.{ExpressionMode.ToString()});" : null)} {(BoundsAsParts && Start != null && !Negate ? $@"if (startMatchData != null) {{ partMatcherData.Parts.Insert(0, startMatchData); }}" : null)} {(BoundsAsParts && End != null && !Negate ? $@"if (endMatchData != null) {{ partMatcherData.Parts.Add(endMatchData); }}" : null)} }} else {{ {(Cacheable ? $@"state.MatchCache[new ValueTuple<string, int>(""{GetEscapedName()}"", startIndex)] = null;" : null)} {(!Negate ? $@"state.CurrentIndex = startIndex; state.DistinctIndex = distinctIndex;" : null)} }} {(Negate ? $@"state.CurrentIndex = startIndex; state.DistinctIndex = distinctIndex;" : null)} {(Cacheable ? $@"}}" : null)} {(Cacheable && !Negate ? $@"else if (success = partMatcherData != null) {{ state.CurrentIndex = partMatcherData.StartIndex + partMatcherData.Length; state.DistinctIndex = partMatcherData.EndDistinctIndex; }}" : null)} {(!Negate ? $@"if (success) {{ {(!IsNoise && FallThrough ? "matchData.Parts.AddRange(partMatcherData.Parts);" : null)} {(!IsNoise && !FallThrough ? "matchData.Parts.Add(partMatcherData);" : null)} {(ClearCache ? "state.MatchCache.Clear();" : null)} }}" : null)} {(generator.LanguageMatcher.LogMatches ? $@"state.MatchLogBuilder.AppendLine($""{{new String('\t', currentId)}} {{state.CurrentIndex}}. {{({(Negate ? "!" : null)}success ? ""Passed"" : ""Failed"")}}: {GetEscapedName()}""); state.Id = currentId - 1;" : null)} return {(Negate ? "!" : null)}success; }}"; method = generator.Add(method, methodName, code); } return(method); }
internal override string Generate(MatcherEngineGenerator generator) => _subPattern.Generate(generator);
private string GenerateMatchFragmentPart(MatcherEngineGenerator generator, IMatcher part) { return(part is FragmentMatcher fragmentMatcher ? fragmentMatcher.Generate(generator) : GenerateMatchPartByTextMatcher(generator, (PatternMatcher)part)); }
private string GenerateMatchFragmentPartsMultipleMode(MatcherEngineGenerator generator) { string methodName = $"MatchFragmentPartsMultipleMode{GetSafeMethodName(Name)}"; string method = $"{methodName}(ref state, partMatcherData)"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); StringBuilder functionText = new StringBuilder(); for (int partIndex = 0; partIndex < Parts.Count; partIndex++) { functionText.AppendLine($@"individualSuccess = {GenerateMatchFragmentPart(generator, Parts[partIndex])}; subSuccess |= individualSuccess; if (individualSuccess) {{ matchCount++; distinctIndex = state.DistinctIndex; delimiterSuccess = {(PartsDelimiter != null ? string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsDelimiter), "range", PartsDelimiterRequired.ToString().ToLower(), "false") : "true")}; goto Break; }} "); } string code = $@"private bool {methodName}(ref State state, FragmentMatchData matchData) {{ bool overallSuccess = false; bool subSuccess = false; bool delimiterSuccess = false; StringMatchData range = default; int matchCount = 0; int distinctIndex = state.DistinctIndex; {(PartsPadding != null ? string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false") : null)}; do {{ subSuccess = false; bool individualSuccess; {functionText.ToString()} Break: overallSuccess |= subSuccess; }} while (subSuccess && delimiterSuccess); if (delimiterSuccess && range != null) {{ state.CurrentIndex = range.StartIndex; state.DistinctIndex = distinctIndex; }} {(PartsPadding != null ? $@"if (overallSuccess) {{ {string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false")}; }}" : null)} bool thresholdSuccess = {MinMatchedParts ?? 1} <= matchCount; bool success = overallSuccess || thresholdSuccess; if ({(!Negate ? "!" : null)}success) {{ state.FailureIndex = Math.Max(state.FailureIndex ?? 0, state.CurrentIndex); }} return success; }}"; method = generator.Add(method, methodName, code); } return(method); }
private string GenerateMatchFragmentPartsOrderedMode(MatcherEngineGenerator generator) { string methodName = $"MatchFragmentPartsOrderedMode{GetSafeMethodName(Name)}"; string method = $"{methodName}(ref state, partMatcherData)"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); StringBuilder functionText = new StringBuilder(); for (int partIndex = 0; partIndex < Parts.Count; partIndex++) { functionText.AppendLine($@"{(partIndex > 0 ? $@"distinctIndex = state.DistinctIndex; partSuccess = {(PartsDelimiter != null ? string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsDelimiter), "stringMatchData", PartsDelimiterRequired.ToString().ToLower(), "false") : "true")}; success = partSuccess; if (!success) {{ goto Break; }}" : null)} success = {GenerateMatchFragmentPart(generator, Parts[partIndex])}; if (!success) {{ if (stringMatchData != null) {{ state.CurrentIndex = stringMatchData.StartIndex; state.DistinctIndex = distinctIndex; }} goto Break; }} else {{ matchCount++; }}"); } string code = $@"private bool {methodName}(ref State state, FragmentMatchData matchData) {{ bool success = true; bool partSuccess; int matchCount = 0; StringMatchData stringMatchData = null; int distinctIndex = state.DistinctIndex; {(PartsPadding != null ? string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false") : null)}; {functionText.ToString()} Break: {(PartsPadding != null ? $@"if (success) {{ {string.Format(generator.LanguageMatcher.GenerateMatchPattern(generator, PartsPadding), "_", "false", "false")}; }}" : null)} success = success || {(MinMatchedParts ?? Parts.Count)} <= matchCount; if ({(!Negate ? "!" : null)}success) {{ state.FailureIndex = Math.Max(state.FailureIndex ?? 0, state.CurrentIndex); }} return success; }}"; method = generator.Add(method, methodName, code); } return(method); }
internal abstract string Generate(MatcherEngineGenerator generator);
internal override string Generate(MatcherEngineGenerator generator) { return("MatchDigit({0}, {1})"); }
internal override string Generate(MatcherEngineGenerator generator) { return("MatchWhitespace({0}, {1})"); }
public string GenerateMatchPattern(MatcherEngineGenerator generator, PatternMatcher pattern) { string methodName = $"MatchPattern{GetSafeMethodName(pattern.Name)}"; string method = $"{methodName}(ref state, out {{0}}, {{1}}, {{2}})"; if (!generator.TryGetMethod(methodName, ref method)) { generator.Add(methodName, method); string code = $@"private bool {methodName}(ref State state, out StringMatchData matchData, bool required, bool readOnly = false) {{ bool success = false; {(generator.IndexingMode != IndexingMode.None ? $@"int distinctIndex = state.DistinctIndex; if (distinctIndex >= state.MaxDistinctIndex) {{" : null)} int length; int startOffset = state.CurrentIndex; (success, length) = {GenerateRawMatchPattern(generator, pattern)}; matchData = default; if (success) {{ matchData = new StringMatchData {{ Name = ""{HttpUtility.JavaScriptStringEncode(pattern.Name)}"", Text = state.Code.Substring(startOffset, length), StartIndex = startOffset, Length = length, IsNoise = {pattern.IsNoise.ToString().ToLower()}, Mergable = {pattern.Mergable.ToString().ToLower()}, Id = {pattern.Id} }}; {(!pattern.IsNoise && generator.IndexingMode != IndexingMode.None ? $@"state.DistinctStringMatches.Add(matchData);" : null)} success = matchData != null; {(generator.IndexingMode == IndexingMode.Lazy ? $@"state.CheckFlags[{pattern.Id}] = distinctIndex + 1;" : null)} {(!pattern.IsNoise && generator.IndexingMode != IndexingMode.None ? $@"state.MaxDistinctIndex++;" : null)} if (!readOnly) {{ {(!pattern.IsNoise && generator.IndexingMode != IndexingMode.None ? $@"state.DistinctIndex++;" : null)} state.CurrentIndex += matchData.Length; }} }} else if (!required) {{ success = true; }} return success; {(generator.IndexingMode != IndexingMode.None ? $@"}} else {{ matchData = state.DistinctStringMatches[distinctIndex]; if (matchData != null) {{ success = matchData.Id == {pattern.Id}; }} else {{ {(generator.IndexingMode == IndexingMode.Eager ? $@"if (state.CheckFlags[{pattern.Id}] < distinctIndex + 1) {{" : null)} int length; int startOffset = state.CurrentIndex; (success, length) = {GenerateRawMatchPattern(generator, pattern)}; if (success) {{ matchData = new StringMatchData {{ Name = ""{GetSafeMethodName(pattern.Name)}"", Text = state.Code.Substring(startOffset, length), StartIndex = startOffset, Length = length, IsNoise = {pattern.IsNoise.ToString().ToLower()}, Mergable = {pattern.Mergable.ToString().ToLower()}, Id = {pattern.Id} }}; {(!pattern.IsNoise ? $@"state.DistinctStringMatches[distinctIndex] = matchData;" : null)} }} {(generator.IndexingMode == IndexingMode.Eager ? $@"state.CheckFlags[{pattern.Id}] = distinctIndex + 1; }}" : null)} }} if (success && !readOnly) {{ {(!pattern.IsNoise ? $@"state.DistinctIndex++;" : null)} state.CurrentIndex += matchData.Length; }} if (!required) {{ success = true; }} return success; }}" : null)} }}"; method = generator.Add(method, methodName, code); } return(method); }
private string GenerateRawMatchPattern(MatcherEngineGenerator generator, PatternMatcher pattern) { return(string.Format(pattern.Generate(generator), "state.Code", "state.CurrentIndex")); }
private string GenerateMatch(MatcherEngineGenerator generator) { return($@" public override MatcherResult Match(string code, string fragmentMatcher, bool matchFullText = true) {{ FragmentMatchData matchData = new FragmentMatchData {{ StartIndex = 0 }}; {(IndexingMode == IndexingMode.Lazy ? $"Span<int> checkFlags = stackalloc int[{Patterns.Count + 1}];" : null)} State state = new State() {{ Code = code{(IndexingMode != IndexingMode.None ? @", DistinctStringMatches = new List<StringMatchData>(2000)" : null)}{(IndexingMode == IndexingMode.Lazy ? @", CheckFlags = checkFlags" : null)}{(Fragments.Any(fragment => fragment.Cacheable) ? @", MatchCache = new Dictionary<ValueTuple<string, int>, FragmentMatchData>()" : null)}{(LogMatches ? $@", MatchLogBuilder = new StringBuilder()" : null)} }}; {(IndexingMode == IndexingMode.Eager ? "PreMatchPatterns(ref state);" : null)} bool success = false; switch (fragmentMatcher) {{ {string.Join("\n", Fragments.Where(matcher => !matcher.FallThrough && !matcher.IsNoise).Select(matcher => $@" case ""{HttpUtility.JavaScriptStringEncode(matcher.Name)}"": success = {matcher.Generate(generator)}; break; "))} }} IMatchData resultMatchData = matchData.Parts.FirstOrDefault(); int? failureIndex = success ? null : state.FailureIndex; if (success && matchFullText && state.CurrentIndex != state.Code.Length) {{ success = false; failureIndex = state.CurrentIndex; }} return new MatcherResult(resultMatchData, success, state.CurrentIndex, failureIndex, state.MatchLogBuilder?.ToString()); }} public override MatcherResult Match(string code, bool matchFullText = true) {{ FragmentMatchData matchData = new FragmentMatchData {{ StartIndex = 0 }}; {(IndexingMode == IndexingMode.Lazy ? $"Span<int> checkFlags = stackalloc int[{Patterns.Count + 1}];" : null)} State state = new State() {{ Code = code{(IndexingMode != IndexingMode.None ? @", DistinctStringMatches = new List<StringMatchData>(2000)" : null)}{(IndexingMode == IndexingMode.Lazy ? @", CheckFlags = checkFlags" : null)}{(Fragments.Any(fragment => fragment.Cacheable) ? @", MatchCache = new Dictionary<ValueTuple<string, int>, FragmentMatchData>()" : null)}{(LogMatches ? $@", MatchLogBuilder = new StringBuilder()" : null)} }}; {(IndexingMode == IndexingMode.Eager ? "PreMatchPatterns(ref state);" : null)} bool success = {StartingFragment.Generate(generator)}; IMatchData resultMatchData = matchData?.Parts.FirstOrDefault(); int? failureIndex = success ? null : state.FailureIndex; if (success && matchFullText && state.CurrentIndex != state.Code.Length) {{ success = false; failureIndex = Math.Max(state.FailureIndex ?? 0, state.CurrentIndex); }} return new MatcherResult(resultMatchData, success, state.CurrentIndex, failureIndex, state.MatchLogBuilder?.ToString()); }} {(IndexingMode == IndexingMode.Eager ? $@"private bool PreMatchPatterns(ref State state) {{ int codeLength = state.Code.Length; bool success = true; bool previousNoise = false; StringMatchData matchData = null; int currentIndex = 0; while ((currentIndex = state.CurrentIndex) < codeLength) {{ success = {string.Join(" ||\n", Patterns.Select(pattern => $@"{string.Format(GenerateMatchPattern(generator, pattern), "matchData", "true", "false")}"))}; if (!success) {{ break; }} else {{ {(generator.LanguageMatcher.LogMatches ? $@"state.MatchLogBuilder.AppendLine($""{{currentIndex}}. Prematched {{matchData.Name}}: {{matchData.Text}}"");" : null)} if (matchData.IsNoise) {{ previousNoise = true; }} else if (previousNoise) {{ if (state.DistinctIndex > 1) {{ StringMatchData previousMatchData = state.DistinctStringMatches[state.DistinctIndex - 2]; if (previousMatchData.Name == matchData.Name && previousMatchData.Mergable) {{ previousMatchData.Text += matchData.Text; previousMatchData.Length = state.CurrentIndex - previousMatchData.StartIndex; state.DistinctIndex--; state.MaxDistinctIndex--; state.DistinctStringMatches.RemoveAt(state.DistinctIndex); }} }} previousNoise = false; }} }} }} state.CurrentIndex = 0; {(IndexingMode != IndexingMode.None ? "state.DistinctIndex = 0;" : null)} return success; }}" : null)}" ); }
private string GetGeneratedClass() { return(MatcherEngineGenerator.GenerateEngine(_languageMatcher)); }