// ______________ // return <value> private GrammarReturn ParseReturn(ref LexerStringReader reader) { reader.MoveBy(Return.Length); var nonTerminalName = new string(reader.ReadTillEndOfWord()); if (_nonTerminals.TryGetValue(nonTerminalName, out var grammarElement) == false) { throw new GrammarParserException($"Non-terminal {nonTerminalName} does not exist."); } return(new GrammarReturn(new GrammarNonTerminalUsage(grammarElement.Name, grammarElement))); }
public void Should_work_with_basic_test_cases(TestCase testCase) { var trie = SearchTrie <Person> .Create(testCase.CaseSensitive, testCase.Map); var reader = new LexerStringReader(testCase.Query, testCase.StartPosition); var found = trie.TryFind(reader, out var person, out var readLength); found.Should().Be(testCase.ShouldBeFound); person.Should().Be(testCase.ExpectedValue); readLength.Should().Be(testCase.ExpectedReadLength); }
// _____________________________ // <value> : Literal|<function-invokation> private GrammarNonTerminalBody ParseNonTerminalBody(ref LexerStringReader reader, GrammarNonTerminal nonTerminal) { var body = new GrammarNonTerminalBody(); var bodyString = new string(reader.ReadTillNewLine()); while (!reader.IsEndOfQuery()) { reader.ReadTillEndOfWhitespace(); if (reader.CurrentChar != OrSeparator && reader.CurrentChar != Assign) { break; } bodyString += new string(reader.ReadTillNewLine()); } var orConditions = bodyString.Split(OrSeparator, StringSplitOptions.RemoveEmptyEntries); foreach (var operandSplitItem in orConditions) { var operand = new GrammarNonTerminalBody.OrConditionOperand(); var blockItems = operandSplitItem.Split(' ', StringSplitOptions.RemoveEmptyEntries); foreach (var blockItem in blockItems) { var bodyItem = ParseNonTerminalBodyItem(blockItem.Trim()); if (bodyItem is GrammarNonTerminalUsage nonTerminalUsage && ReferenceEquals(nonTerminal, nonTerminalUsage.Impl)) { operand.IsRecursive = true; } operand.Add(bodyItem); } body.OrConditionOperands.Add(operand); } return(body); }
private GrammarReturn ParseImpl() { GrammarReturn final = null; var reader = new LexerStringReader(_grammar, 0); while (reader.IsInRange()) { if (reader.IsEndOfLine()) { reader.MoveNext(); continue; } if (reader.StartsWith(Comment.AsSpan())) { reader.MoveToNextLine(); continue; } reader.ReadTillEndOfWhitespace(); if (reader.StartsWith(GrammarNonTerminalStart.ToString().AsSpan())) { // _______________________________________ // <value> : Literal|<function-invokation> var nonTerminalName = new string(reader.ReadTillEndOfWord()); // <value> if (nonTerminalName.EndsWith(GrammarNonTerminalEnd) == false) { throw new GrammarParserException($"Non-terminal {nonTerminalName} name " + $"should finish with {GrammarNonTerminalEnd}"); } var nonTerminal = GetNonTerminalByName(nonTerminalName); if (nonTerminal.FullyParsed) { throw new GrammarParserException($"Cannot declare {nonTerminalName} more than once."); } // skip ':' var assign = new string(reader.ReadWhile(x => x != Assign)) + reader.CurrentChar; if (assign.EndsWith(Assign) == false) { throw new GrammarParserException($"Invalid syntax for {nonTerminalName}."); } reader.MoveNext(); reader.ReadTillEndOfWhitespace(); nonTerminal.Body = ParseNonTerminalBody(ref reader, nonTerminal); continue; } if (reader.StartsWith(Return.AsSpan())) { final = ParseReturn(ref reader); break; } throw new GrammarParserException($"Invalid grammar syntax. Line: {new string(reader.ReadTillNewLine())}"); } if (final == null) { throw new GrammarParserException("Return statement not found."); } var notExistingNonTerminal = _nonTerminals.Select(x => x.Value).FirstOrDefault(x => x.FullyParsed == false); if (notExistingNonTerminal != null) { throw new GrammarParserException($"Non-terminal '{notExistingNonTerminal.Name}' " + "is not declared. Are you sure your gramma is fine?"); } foreach (var nonTerminal in _nonTerminals.Select(x => x.Value)) { if (nonTerminal.Body.OrConditionOperands.All(x => x.IsRecursive)) { var msg = $"Infinite recursion detected in {nonTerminal.Name} non-terminal. " + "Use '|' to create escape path."; throw new GrammarParserException(msg); } } return(final); }