Пример #1
0
        // ______________
        // 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)));
        }
Пример #2
0
        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);
        }
Пример #3
0
        //           _____________________________
        // <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);
        }
Пример #4
0
        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);
        }