예제 #1
0
        public void BracketPairs_Should_Generate2_N_2()
        {
            BracketPairs bp = new BracketPairs();

            var results = bp.GenerateBracketPairs2(2);

            results.Should().NotBeNull("results should not be null with n = 2 in recursive2");
            results.Count.Should().Be(2, "results should have exactly 2 results with n = 2 in recursive2");
            results.Contains("(())").Should().BeTrue("results does not contain value (()) with n = 2 in recursive2");
            results.Contains("()()").Should().BeTrue("results does not contain value ()() with n = 2 in recursive2");
        }
예제 #2
0
        public void BracketPairs_Should_Generate_N_0()
        {
            BracketPairs bp = new BracketPairs();

            var results = bp.GenerateBracketPairs(0, true);

            results.Should().NotBeNull("results should not be null with n = 0 in recursive");
            results.Count.Should().Be(0, "results should have exactly 0 result with n = 0 in recursive");

            results = bp.GenerateBracketPairs(0, false);
            results.Should().NotBeNull("results should not be null with n = 0 in iterative");
            results.Count.Should().Be(0, "results should have exactly 0 result with n = 0 in iterative");
        }
예제 #3
0
        public void BracketPairs_Should_Generate_N_1()
        {
            BracketPairs bp = new BracketPairs();

            var results = bp.GenerateBracketPairs(1, true);

            results.Should().NotBeNull("results should not be null with n = 1 in recursive");
            results.Count.Should().Be(1, "results should have exactly 1 result with n = 1 in recursive");
            results[0].Should().Be("()", "results was not incorrect with n = 1 in recursive");

            results = bp.GenerateBracketPairs(1, false);
            results.Should().NotBeNull("results should not be null with n = 1 in iterative");
            results.Count.Should().Be(1, "results should have exactly 1 result with n = 1 in iterative");
            results[0].Should().Be("()", "results was not incorrect with n = 1 in iterative");
        }
예제 #4
0
        public void BracketPairs_Should_Generate_N_3()
        {
            BracketPairs bp = new BracketPairs();

            var results = bp.GenerateBracketPairs(3, true);

            results.Should().NotBeNull("results should not be null with n = 3 in recursive");
            results.Count.Should().Be(5, "results should have exactly 5 results with n = 3 in recursive");
            results.Contains("((()))").Should().BeTrue("results does not contain value ((())) with n = 3 in recursive");
            results.Contains("(())()").Should().BeTrue("results does not contain value (())() with n = 3 in recursive");
            results.Contains("()(())").Should().BeTrue("results does not contain ()(()) with n = 3 in recursive");
            results.Contains("(()())").Should().BeTrue("results does not contain value (()()) with n = 3 in recursive");
            results.Contains("()()()").Should().BeTrue("results does not contain value ()()() with n = 3 in recursive");

            results = bp.GenerateBracketPairs(3, false);
            results.Should().NotBeNull("results should not be null with n = 3 in iterative");
            results.Count.Should().Be(5, "results should have exactly 5 results with n = 3 in iterative");
            results.Contains("((()))").Should().BeTrue("results does not contain value ((())) with n = 3 in iterative");
            results.Contains("(())()").Should().BeTrue("results does not contain value (())() with n = 3 in iterative");
            results.Contains("()(())").Should().BeTrue("results does not contain ()(()) with n = 3 in iterative");
            results.Contains("(()())").Should().BeTrue("results does not contain value (()()) with n = 3 in iterative");
            results.Contains("()()()").Should().BeTrue("results does not contain value ()()() with n = 3 in iterative");
        }
예제 #5
0
        public IEnumerable<Token<TokenType>> ReadToScopeClose(TokenType open, TokenType close, BracketPairs bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token<TokenType> token = null;
            while (!End)
            {
                token = ReadToken();
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Allows nesting
                {
                    _stack.Push(token);
                }
                else if (bracketPairs.ContainsClosing(token.Identifier) || token.Identifier == close) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any() && token.Identifier == close)
                    {
                        yield break;
                    }

                    var lastOpening = _stack.Pop();
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier))
                    {
                        throw new ManhoodException(_source, token,
                            "Invalid closure '"
                            + lastOpening.Value
                            + " ... "
                            + token.Value
                            + "' - expected '"
                            + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier))
                            + "'");
                    }
                }
                yield return token;
            }
            throw new ManhoodException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }
예제 #6
0
        public IEnumerable<IEnumerable<Token<TokenType>>> ReadItemsToClosureTrimmed(TokenType open, TokenType close, TokenType separator, BracketPairs bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token<TokenType> token = null;

            int start = _pos;
            while (!End)
            {
                token = PeekToken();
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Allows nesting
                {
                    _stack.Push(token);
                }
                else if (bracketPairs.ContainsClosing(token.Identifier) || token.Identifier == close) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any() && token.Identifier == close)
                    {
                        yield return _tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray();
                        _pos++;
                        yield break;
                    }

                    var lastOpening = _stack.Pop();
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier))
                    {
                        throw new ManhoodException(_source, token,
                            "Invalid closure '"
                            + lastOpening.Value
                            + " ... "
                            + token.Value
                            + "' - expected '"
                            + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier))
                            + "'");
                    }
                }
                else if (token.Identifier == separator && !_stack.Any())
                {
                    yield return _tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray();
                    _pos++;
                    TakeAll(TokenType.Whitespace);
                    start = _pos;
                    continue;
                }

                _pos++;
            }
            throw new ManhoodException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }
예제 #7
0
        public IEnumerable<IEnumerable<Token<TokenType>>> ReadMultiItemScope(TokenType open, TokenType close, TokenType separator, BracketPairs bracketPairs)
        {
            _stack.Clear();
            // This exception should not happen when running patterns - only if I mess something up in the code.
            if (!IsNext(open)) throw new InvalidOperationException("The specified opening token does not occur at the reader position.");

            int start = _pos + 1;
            Token<TokenType> token = null;

            while (!End)
            {
                // Peek but don't consume - this saves some calculations later on.
                token = PeekToken();

                // Opening bracket
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Previous bracket allows nesting
                {
                    _stack.Push(token);
                }

                // Closing bracket
                else if (bracketPairs.ContainsClosing(token.Identifier) || close == token.Identifier) // Previous bracket allows nesting
                {
                    var lastOpening = _stack.Pop();

                    // Handle invalid closures
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier)) // Not in main pair
                    {
                        throw new ManhoodException(_source, token, 
                            "Invalid closure '"
                            + lastOpening.Value
                            + " ... " 
                            + token.Value 
                            + "' - expected '" 
                            + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier)) 
                            + "'");
                    }

                    // If the _stack is empty, this is the last item. Stop the iterator.
                    if (!_stack.Any())
                    {
                        yield return _tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray();
                        _pos++;
                        yield break;
                    }
                }

                // Separator
                else if (token.Identifier == separator && _stack.Count == 1)
                {
                    yield return _tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray();
                    start = _pos + 1;
                }

                // Move to next position
                _pos++;
            }
            throw new ManhoodException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }
        private void TryParse()
        {
            string      text       = Text;
            int         count      = text.Length;
            int         nestLevel  = 0;
            Stack <int> unbalanced = new Stack <int>();

            for (int index = 0; index < count; ++index)
            {
                char c = text[index];
                if (c == '(' || c == '[' || c == '{' || c == '<')
                {
                    unbalanced.Push(index);
                    nestLevel++;
                }
                else if (c == ')' || c == ']' || c == '}' || c == '>')
                {
                    nestLevel--;
                    char closeChar = c;
                    if (unbalanced.Count == 0)
                    {
                        Exceptions.Add(new Exception("Unbalanced close symbol at index " + index));
                        return;
                    }
                    int  openIndex        = unbalanced.Peek();
                    char openChar         = text[openIndex];
                    char expectedOpenChar = '\0';
                    switch (closeChar)
                    {
                    case ')':
                        expectedOpenChar = '(';
                        break;

                    case ']':
                        expectedOpenChar = '[';
                        break;

                    case '}':
                        expectedOpenChar = '{';
                        break;

                    case '>':
                        expectedOpenChar = '<';
                        break;
                    }
                    if (openChar != expectedOpenChar)
                    {
                        Exceptions.Add(new Exception("Mismatched close symbol " + closeChar + " at " + index +
                                                     ". The open symbol is " + openChar + " at " + openIndex + "."));
                        return;
                    }
                    var pair = new BracketPair()
                    {
                        OpenChar   = openChar,
                        OpenIndex  = openIndex,
                        CloseChar  = closeChar,
                        CloseIndex = index,
                        NestLevel  = (nestLevel + 1)
                    };
                    BracketPairs.Add(pair);
                    unbalanced.Pop();
                }
            }
            BracketPairs.Sort((BracketPair p1, BracketPair p2) => (p1.OpenIndex - p2.OpenIndex));
        }
예제 #9
0
        public IEnumerable <Token <TokenType> > ReadToScopeClose(TokenType open, TokenType close, BracketPairs bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token <TokenType> token = null;

            while (!End)
            {
                token = ReadToken();
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Allows nesting
                {
                    _stack.Push(token);
                }
                else if (bracketPairs.ContainsClosing(token.Identifier) || token.Identifier == close) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any() && token.Identifier == close)
                    {
                        yield break;
                    }

                    var lastOpening = _stack.Pop();
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier))
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier))
                                                + "'");
                    }
                }
                yield return(token);
            }
            throw new RantException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }
예제 #10
0
        public IEnumerable <IEnumerable <Token <TokenType> > > ReadItemsToClosureTrimmed(TokenType open, TokenType close, TokenType separator, BracketPairs bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token <TokenType> token = null;

            int start = _pos;

            while (!End)
            {
                token = PeekToken();
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Allows nesting
                {
                    _stack.Push(token);
                }
                else if (bracketPairs.ContainsClosing(token.Identifier) || token.Identifier == close) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any() && token.Identifier == close)
                    {
                        yield return(_tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray());

                        _pos++;
                        yield break;
                    }

                    var lastOpening = _stack.Pop();
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier))
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier))
                                                + "'");
                    }
                }
                else if (token.Identifier == separator && !_stack.Any())
                {
                    yield return(_tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray());

                    _pos++;
                    TakeAll(TokenType.Whitespace);
                    start = _pos;
                    continue;
                }

                _pos++;
            }
            throw new RantException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }
예제 #11
0
        public IEnumerable <IEnumerable <Token <TokenType> > > ReadMultiItemScope(TokenType open, TokenType close, TokenType separator, BracketPairs bracketPairs)
        {
            _stack.Clear();
            // This exception should not happen when running patterns - only if I mess something up in the code.
            if (!IsNext(open))
            {
                throw new InvalidOperationException("The specified opening token does not occur at the reader position.");
            }

            int start = _pos + 1;
            Token <TokenType> token = null;

            while (!End)
            {
                // Peek but don't consume - this saves some calculations later on.
                token = PeekToken();

                // Opening bracket
                if (bracketPairs.ContainsOpening(token.Identifier) || open == token.Identifier) // Previous bracket allows nesting
                {
                    _stack.Push(token);
                }

                // Closing bracket
                else if (bracketPairs.ContainsClosing(token.Identifier) || close == token.Identifier) // Previous bracket allows nesting
                {
                    var lastOpening = _stack.Pop();

                    // Handle invalid closures
                    if (!bracketPairs.Contains(lastOpening.Identifier, token.Identifier)) // Not in main pair
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + Lexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.Identifier))
                                                + "'");
                    }

                    // If the _stack is empty, this is the last item. Stop the iterator.
                    if (!_stack.Any())
                    {
                        yield return(_tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray());

                        _pos++;
                        yield break;
                    }
                }

                // Separator
                else if (token.Identifier == separator && _stack.Count == 1)
                {
                    yield return(_tokens.SkipWhile((t, i) => i < start).TakeWhile((t, i) => i < _pos - start).ToArray());

                    start = _pos + 1;
                }

                // Move to next position
                _pos++;
            }
            throw new RantException(_source, null, "Unexpected end of file - expected '" + Lexer.Rules.GetSymbolForId(close) + "'.");
        }