private void TryParsePredicateObjectList(SparqlQueryParserContext context, GraphPattern p, int expectedCount)
        {
            PatternItem subj, pred, obj;
            
            //Subject is first thing on the Stack
            subj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());

            //Start grabbing other stuff off the Stack and Parsing
            IToken next, lit, temp;
            ISparqlPath path;

            do
            {
                //Peek at the Next Token
                next = context.Tokens.Peek();
                switch (next.TokenType)
                {
                    case Token.COMMENT:
                        //Ignore Comments
                        context.Tokens.Dequeue();
                        break;

                    case Token.VARIABLE:
                        context.LocalTokens.Push(next);
                        context.Query.AddVariable(next.Value);
                        context.Tokens.Dequeue();
                        break;

                    case Token.URI:
                    case Token.QNAME:
                    case Token.LITERAL:
                    case Token.LONGLITERAL:
                    case Token.PLAINLITERAL:
                    case Token.KEYWORDA:
                        context.LocalTokens.Push(next);
                        context.Tokens.Dequeue();
                        break;

                    case Token.HAT:
                    case Token.DIVIDE:
                    case Token.BITWISEOR:
                    case Token.MULTIPLY:
                    case Token.PLUS:
                    case Token.QUESTION:
                    case Token.NEGATION:
                        //If we see any of these Tokens then it's a Property Path
                        if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Property Paths are not permitted in SPARQL 1.0");

                        if (context.LocalTokens.Count == expectedCount - 1)
                        {
                            path = context.PathParser.Parse(context, context.LocalTokens.Pop());
                            PathToken pathToken = new PathToken(path);
                            context.LocalTokens.Push(pathToken);
                        }
                        else if ((next.TokenType == Token.HAT || next.TokenType == Token.NEGATION) && context.LocalTokens.Count == expectedCount - 2)
                        {
                            // ^ and ! may be used to start a pattern
                            context.Tokens.Dequeue();
                            path = context.PathParser.Parse(context, next);
                            PathToken pathToken = new PathToken(path);
                            context.LocalTokens.Push(pathToken);
                        }
                        else
                        {
                            throw ParserHelper.Error("Encountered a '" + next.GetType().ToString() + "' Token which is valid only after a Predicate to indicate Path Cardinality", next);
                        }
                        break;

                    case Token.BLANKNODE:
                    case Token.BLANKNODEWITHID:
                        //Generate a new Blank Node ID if required
                        if (next.TokenType == Token.BLANKNODE)
                        {
                            next = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), 0, 0, 0);
                        }

                        //Check list of Blank Node usages
                        if (context.BlankNodeIDUsages.ContainsKey(next.Value))
                        {
                            if (context.BlankNodeIDUsages[next.Value] != context.GraphPatternID)
                            {
                                throw ParserHelper.Error("Invalid use of Blank Node Label '" + next.Value + "', this Label has already been used in a different Graph Pattern", next);
                            }
                        }
                        else
                        {
                            context.BlankNodeIDUsages.Add(next.Value, context.GraphPatternID);
                        }

                        context.LocalTokens.Push(next);
                        context.Tokens.Dequeue();
                        break;

                    case Token.HATHAT:
                        //Get the next Token which should be a Datatype Token
                        context.Tokens.Dequeue();
                        next = context.Tokens.Peek();
                        if (next.TokenType == Token.DATATYPE)
                        {
                            //Get the previous Token off the Stack and ensure it's a Literal
                            lit = context.LocalTokens.Pop();
                            if (lit.TokenType == Token.LITERAL || lit.TokenType == Token.LONGLITERAL)
                            {
                                //Create a DataTyped Literal
                                context.LocalTokens.Push(new LiteralWithDataTypeToken(lit, (DataTypeToken)next));
                            }
                            else
                            {
                                throw ParserHelper.Error("Unexpected Datatype Token, a Datatype may only be specified after a quoted Literal/Long Literal", lit);
                            }
                        }
                        else
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Datatype Token to follow a ^^ Token to specify the Datatype of a previous Literal Token", next);
                        }
                        context.Tokens.Dequeue();
                        break;

                    case Token.LEFTSQBRACKET:
                        //Start of Blank Node Collection
                        //Create a new Blank Node Token
                        BlankNodeWithIDToken bnode = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), 0, 0, 0);

                        //Push twice, once for Object of the current Triple
                        context.LocalTokens.Push(bnode);

                        context.Tokens.Dequeue();
                        next = context.Tokens.Peek();
                        if (next.TokenType == Token.RIGHTSQBRACKET)
                        {
                            //Single anonymous blank node
                            context.Tokens.Dequeue();
                            break;
                        }

                        //Blank Node Collection
                        //Push again for Subject of new Triple
                        context.LocalTokens.Push(bnode);

                        //Recursively call self to parse the new Triple list
                        this.TryParsePredicateObjectList(context, p, expectedCount + 2);
                        break;

                    case Token.RIGHTSQBRACKET:
                        //End of Blank Node Collection

                        //Allow for trailing semicolon
                        if (context.LocalTokens.Count == expectedCount - 2 && context.Tokens.LastTokenType == Token.SEMICOLON)
                        {
                            context.Tokens.Dequeue();
                            return;
                        }

                        //Check length of Stack
                        if (context.LocalTokens.Count < expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Right Square Bracket Token to terminate a Blank Node Collection within a Triple Pattern but there are not enough Tokens to form a valid Triple Pattern", next);
                        }
                        else if (context.LocalTokens.Count > expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Right Square Bracket Token to terminate a Blank Node Collection within a Triple Pattern but there are too many Tokens to form a valid Triple Pattern", next);
                        }
                        obj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());
                        pred = this.TryCreatePatternItem(context, context.LocalTokens.Pop());

                        //Add Pattern to the Graph Pattern
                        p.AddTriplePattern(new TriplePattern(subj, pred, obj));
                        context.Tokens.Dequeue();
                        return;

                    case Token.LEFTBRACKET:
                        //Property Path if it's the Predicate or Collection if it's the Object
                        if (context.LocalTokens.Count == expectedCount - 2)
                        {
                            //Property Path
                            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Property Paths are not permitted in SPARQL 1.0");
 
                            path = context.PathParser.Parse(context, context.Tokens.Dequeue());
                            PathToken pathToken = new PathToken(path);
                            context.LocalTokens.Push(pathToken);
                        }
                        else
                        {
                            //Collection
                            context.Tokens.Dequeue();
                            this.TryParseCollection(context, p, false);
                        }
                        break;

                    case Token.LANGSPEC:
                        //Get the previous Token off the Stack and ensure it's a Literal
                        lit = context.LocalTokens.Pop();
                        if (lit.TokenType == Token.LITERAL || lit.TokenType == Token.LONGLITERAL)
                        {
                            //Create a Language Specified Literal
                            context.LocalTokens.Push(new LiteralWithLanguageSpecifierToken(lit, (LanguageSpecifierToken)next));
                        }
                        else
                        {
                            throw ParserHelper.Error("Unexpected Language Specifier Token, a Language Specifier may only be specified after a quoted Literal/Long Literal", lit);
                        }
                        context.Tokens.Dequeue();
                        break;

                    case Token.COMMA:
                        //End of a Triple Pattern

                        //Check length of stack
                        if (context.LocalTokens.Count < expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Comma Token to terminate a Triple Pattern but there are not enough Tokens to form a valid Triple Pattern", next);
                        }
                        else if (context.LocalTokens.Count > expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Comma Token to terminate a Triple Pattern but there are too many Tokens to form a valid Triple Pattern", next);
                        }
                        obj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());
                        temp = context.LocalTokens.Pop();
                        if (temp.TokenType == Token.PATH)
                        {
                            path = ((PathToken)temp).Path;
                            p.AddTriplePattern(new PropertyPathPattern(subj, path, obj));
                        }
                        else
                        {
                            pred = this.TryCreatePatternItem(context, temp);

                            //Add Pattern to the Graph Pattern
                            p.AddTriplePattern(new TriplePattern(subj, pred, obj));
                        }

                        //Push Predicate back on Stack
                        context.LocalTokens.Push(temp);

                        context.Tokens.Dequeue();
                        break;

                    case Token.SEMICOLON:
                        //End of a Triple Pattern

                        //Check length of stack
                        if (context.LocalTokens.Count < expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Semicolon Token to terminate a Triple Pattern but there are not enough Tokens to form a valid Triple Pattern", next);
                        }
                        else if (context.LocalTokens.Count > expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Semicolon Token to terminate a Triple Pattern but there are too many Tokens to form a valid Triple Pattern", next);
                        }
                        obj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());
                        temp = context.LocalTokens.Pop();
                        if (temp.TokenType == Token.PATH)
                        {
                            path = ((PathToken)temp).Path;
                            p.AddTriplePattern(new PropertyPathPattern(subj, path, obj));
                        }
                        else
                        {
                            pred = this.TryCreatePatternItem(context, temp);

                            //Add Pattern to the Graph Pattern
                            p.AddTriplePattern(new TriplePattern(subj, pred, obj));
                        }

                        context.Tokens.Dequeue();
                        break;

                    case Token.DOT:
                        //End of the Triple Patterns

                        //Allow for trailing semicolon and Blank Node Collection lists
                        if (context.LocalTokens.Count == expectedCount - 2 && (context.Tokens.LastTokenType == Token.SEMICOLON || (context.Tokens.LastTokenType == Token.RIGHTSQBRACKET && p.TriplePatterns.Count > 0)))
                        {
                            if (context.Tokens.LastTokenType == Token.RIGHTSQBRACKET)
                            {
                                context.Tokens.Dequeue();
                            }
                            return;
                        }

                        //Check length of Stack
                        if (context.LocalTokens.Count < expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a DOT Token to terminate a Triple Pattern but there are not enough Tokens to form a valid Triple Pattern", next);
                        }
                        else if (context.LocalTokens.Count > expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a DOT Token to terminate a Triple Pattern but there are too many Tokens to form a valid Triple Pattern", next);
                        }
                        obj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());
                        temp = context.LocalTokens.Pop();
                        if (temp.TokenType == Token.PATH)
                        {
                            path = ((PathToken)temp).Path;
                            p.AddTriplePattern(new PropertyPathPattern(subj, path, obj));
                        }
                        else
                        {
                            pred = this.TryCreatePatternItem(context, temp);

                            //Add Pattern to the Graph Pattern
                            p.AddTriplePattern(new TriplePattern(subj, pred, obj));
                        }
                        context.Tokens.Dequeue();
                        return;

                    case Token.LEFTCURLYBRACKET:
                    case Token.RIGHTCURLYBRACKET:
                    case Token.OPTIONAL:
                    case Token.EXISTS:
                    case Token.NOTEXISTS:
                    case Token.UNSAID:
                    case Token.MINUS_P:
                    case Token.SERVICE:
                    case Token.GRAPH:
                    case Token.FILTER:
                        //End of the Triple Patterns

                        //Allow for trailing semicolon and Blank Node Collection lists
                        if (context.LocalTokens.Count == expectedCount - 2 && (context.Tokens.LastTokenType == Token.SEMICOLON || ((context.Tokens.LastTokenType == Token.RIGHTSQBRACKET || context.Tokens.LastTokenType == Token.RIGHTBRACKET) && p.TriplePatterns.Count > 0)))
                        {
                            return;
                        }

                        //Check length of Stack
                        if (context.LocalTokens.Count < expectedCount)
                        {
                            temp = context.LocalTokens.Peek();
                            if (next.TokenType == Token.LEFTCURLYBRACKET && context.SyntaxMode != SparqlQuerySyntax.Sparql_1_0 && context.LocalTokens.Count == expectedCount - 1 && (temp.TokenType == Token.QNAME || temp.TokenType == Token.URI || temp.TokenType == Token.KEYWORDA))
                            {
                                //In this case this should be a Cardinality Modifier on a path (we hope)
                                path = context.PathParser.Parse(context, context.LocalTokens.Pop());
                                IToken pathToken = new PathToken(path);
                                context.LocalTokens.Push(pathToken);
                                continue;
                            }
                            else
                            {
                                throw ParserHelper.Error("Encountered a Token which terminates a Triple Pattern but there are not enough Tokens to form a valid Triple Pattern", next);
                            }
                        }
                        else if (context.LocalTokens.Count > expectedCount)
                        {
                            throw ParserHelper.Error("Encountered a Token which terminates a Triple Pattern but there are too many Tokens to form a valid Triple Pattern", next);
                        }
                        obj = this.TryCreatePatternItem(context, context.LocalTokens.Pop());
                        temp = context.LocalTokens.Pop();
                        if (temp.TokenType == Token.PATH)
                        {
                            path = ((PathToken)temp).Path;
                            p.AddTriplePattern(new PropertyPathPattern(subj, path, obj));
                        }
                        else
                        {
                            pred = this.TryCreatePatternItem(context, temp);

                            //Add Pattern to the Graph Pattern
                            p.AddTriplePattern(new TriplePattern(subj, pred, obj));
                        }
                        return;
                    
                    default:
                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' while trying to Parse Triple Patterns", next);
                }
            } while (true);

        }
        private void TryParseCollection(SparqlQueryParserContext context, GraphPattern p, bool nested)
        {

            //Check the next Token
            IToken next = context.Tokens.Peek();
            if (next.TokenType == Token.RIGHTBRACKET)
            {
                //Empty Collection
                context.Tokens.Dequeue();

                if (!nested)
                {
                    //Push an rdf:nil Uri on the Stack
                    context.LocalTokens.Push(new UriToken("<" + NamespaceMapper.RDF + "nil>", next.StartLine, next.StartPosition, next.EndPosition));
                }
            }
            else
            {
                //Push a Blank Node Token onto the stack for the start of the collection
                BlankNodeWithIDToken blank; 
                if (!nested)
                {
                    blank = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);
                    context.LocalTokens.Push(blank);
                } 
                else 
                {
                    blank = new BlankNodeWithIDToken("_:sparql-autos" + context.BlankNodeID, next.StartLine, next.StartPosition, next.EndPosition);
                }

                bool first = true;

                IUriNode rdfFirst, rdfRest, rdfNil;
                rdfFirst = new UriNode(null, new Uri(NamespaceMapper.RDF + "first"));
                rdfRest = new UriNode(null, new Uri(NamespaceMapper.RDF + "rest"));
                rdfNil = new UriNode(null, new Uri(NamespaceMapper.RDF + "nil"));

                do
                {
                    next = context.Tokens.Peek();

                    switch (next.TokenType)
                    {
                        case Token.BLANKNODE:
                        case Token.BLANKNODEWITHID:
                        case Token.KEYWORDA:
                        case Token.LITERAL:
                        case Token.LONGLITERAL:
                        case Token.PLAINLITERAL:
                        case Token.QNAME:
                        case Token.URI:
                        case Token.VARIABLE:
                            //Create the Triple pattern

                            if (first)
                            {
                                //rdf:first Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, next)));
                                first = false;
                            }
                            else
                            {
                                //Get new Blank Node ID
                                BlankNodeWithIDToken blank2 = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine,next.StartPosition,next.EndPosition);

                                //rdf:rest Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfRest), this.TryCreatePatternItem(context, blank2)));

                                blank = blank2;

                                //rdf:first Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, next)));
                            }

                            break;

                        case Token.LEFTSQBRACKET:
                            //Is the next token a Right Square Bracket?
                            //ie. a [] for an anonymous blank node
                            context.Tokens.Dequeue();
                            next = context.Tokens.Peek();

                            if (next.TokenType == Token.RIGHTSQBRACKET)
                            {
                                BlankNodeWithIDToken anon = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                                if (first)
                                {
                                    //rdf:first Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, anon)));
                                    first = false;
                                }
                                else
                                {
                                    //Get new Blank Node ID
                                    BlankNodeWithIDToken blank2 = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                                    //rdf:rest Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfRest), this.TryCreatePatternItem(context, blank2)));

                                    blank = blank2;

                                    //rdf:first Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, anon)));
                                }
                            }
                            else
                            {
                                BlankNodeWithIDToken anon = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                                if (first)
                                {
                                    //rdf:first Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, anon)));
                                    first = false;
                                }
                                else
                                {
                                    //Get new Blank Node ID
                                    BlankNodeWithIDToken blank2 = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                                    //rdf:rest Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfRest), this.TryCreatePatternItem(context, blank2)));

                                    blank = blank2;

                                    //rdf:first Pattern
                                    p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, anon)));
                                }

                                //Parse the Blank Node Collection
                                context.LocalTokens.Push(anon);
                                this.TryParsePredicateObjectList(context, p, context.LocalTokens.Count + 1);
                                continue;
                            }
                            break;

                        case Token.LEFTBRACKET:

                            BlankNodeWithIDToken innerCollection = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                            if (first)
                            {
                                //rdf:first Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, innerCollection)));
                                first = false;
                            }
                            else
                            {
                                //Get new Blank Node ID
                                BlankNodeWithIDToken blank2 = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), next.StartLine, next.StartPosition, next.EndPosition);

                                //rdf:rest Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfRest), this.TryCreatePatternItem(context, blank2)));

                                blank = blank2;

                                //rdf:first Pattern
                                p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfFirst), this.TryCreatePatternItem(context, innerCollection)));
                            }

                            context.Tokens.Dequeue();
                            this.TryParseCollection(context, p, true);
                            continue;

                        case Token.RIGHTBRACKET:
                            //End of Collection

                            //rdf:rest Pattern
                            p.AddTriplePattern(new TriplePattern(this.TryCreatePatternItem(context, blank), new NodeMatchPattern(rdfRest), new NodeMatchPattern(rdfNil)));
                            break;

                        default:
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered while trying to parse a Collection", next);
                    }

                    context.Tokens.Dequeue();
                } while (next.TokenType != Token.RIGHTBRACKET);
            }
        }
        private void TryParseTriplePatterns(SparqlQueryParserContext context, GraphPattern p)
        {
            int lasttoken = context.Tokens.LastTokenType;
            IToken next = context.Tokens.Dequeue();

            //Allowed a Variable/RDF Term/Collection
            //OR we might go straight to a OPTIONAL/GRAPH/UNION/FILTER/EXISTS/NOT EXISTS/LET

            switch (next.TokenType)
            {
                case Token.COMMENT:
                    //Comments are discardable
                    this.TryParseTriplePatterns(context, p);
                    break;

                case Token.VARIABLE:
                    //Variable
                    context.LocalTokens.Push(next);
                    context.Query.AddVariable(next.Value);
                    this.TryParsePredicateObjectList(context, p,2);
                    break;

                case Token.URI:
                case Token.QNAME:
                case Token.LITERAL:
                case Token.LONGLITERAL:
                case Token.PLAINLITERAL:
                    //Must then be followed be a non-empty Property List
                    context.LocalTokens.Push(next);
                    this.TryParsePredicateObjectList(context, p,2);
                    break;

                case Token.BLANKNODE:
                case Token.BLANKNODEWITHID:
                    //Check list of Blank Node usages
                    if (context.BlankNodeIDUsages.ContainsKey(next.Value))
                    {
                        if (context.BlankNodeIDUsages[next.Value] != context.GraphPatternID)
                        {
                            throw ParserHelper.Error("Invalid use of Blank Node Label '" + next.Value + "', this Label has already been used in a different Graph Pattern", next);
                        }
                    }
                    else
                    {
                        context.BlankNodeIDUsages.Add(next.Value, context.GraphPatternID);
                    }

                    //Must then be followed be a non-empty Property List
                    context.LocalTokens.Push(next);
                    this.TryParsePredicateObjectList(context, p, 2);
                    break;

                case Token.LET:
                    //LET assignment
                    this.TryParseLetAssignment(context, p);
                    break;

                case Token.BIND:
                    //BIND assignment
                    this.TryParseBindAssignment(context, p);
                    break;

                case Token.LEFTSQBRACKET:
                    //Start of Blank Node Collection
                    //Create a new Blank Node Token
                    BlankNodeWithIDToken bnode = new BlankNodeWithIDToken(context.GetNewBlankNodeID(), 0, 0, 0);

                    //Push twice, once for Subject of Collection
                    context.LocalTokens.Push(bnode);

                    next = context.Tokens.Peek();
                    if (next.TokenType == Token.RIGHTSQBRACKET)
                    {
                        //Single anonymous blank node
                        context.Tokens.Dequeue();

                        //Parse as Subject of Triples
                        this.TryParsePredicateObjectList(context, p, 2);
                    }
                    else
                    {

                        //Parse the Collection
                        this.TryParsePredicateObjectList(context, p, 2);

                        //Push again for subject of Triples
                        context.LocalTokens.Push(bnode);
                        this.TryParsePredicateObjectList(context, p, 2);
                    }
                    break;

                case Token.LEFTBRACKET:
                    //Collection
                    this.TryParseCollection(context, p, false);
                    this.TryParsePredicateObjectList(context, p, 2);
                    break;

                case Token.FILTER:
                    //FILTER Pattern
                    this.TryParseFilterClause(context, p);
                    break;

                case Token.OPTIONAL:
                    //OPTIONAL Clause
                    this.TryParseOptionalClause(context, p);
                    break;

                case Token.EXISTS:
                case Token.NOTEXISTS:
                case Token.UNSAID:
                    //EXISTS/NOT EXISTS clause
                    if (next.TokenType == Token.UNSAID && context.SyntaxMode != SparqlQuerySyntax.Extended) throw new RdfParseException("The UNSAID Keyword is only supported when syntax is set to Extended.  It is an alias for NOT EXISTS which can be used when the syntax is set to SPARQL 1.1/Extended");
                    this.TryParseExistsClause(context, p, (next.TokenType == Token.EXISTS));
                    break;

                case Token.MINUS_P:
                    //MINUS clause
                    this.TryParseMinusClause(context, p);
                    break;

                case Token.SERVICE:
                    //SERVICE clause
                    this.TryParseServiceClause(context, p);
                    break;

                case Token.SELECT:
                    //Sub-query
                    this.TryParseSubquery(context, p);
                    break;

                case Token.GRAPH:
                    //GRAPH Clause
                    this.TryParseGraphClause(context, p);
                    break;

                case Token.UNION:
                    //UNION Clause
                    this.TryParseUnionClause(context, p);
                    break;

                case Token.LEFTCURLYBRACKET:
                    //Nested Graph Pattern
                    p.AddGraphPattern(this.TryParseGraphPattern(context, false));

                    //Simplify Subqueries
                    if (p.ChildGraphPatterns.Last().IsSubQuery)
                    {
                        GraphPattern temp = p.LastChildPattern();
                        p.AddTriplePattern(temp.TriplePatterns.First());
                    }
                    break;

                case Token.DOT:
                    //Can Discard this if last character was the end of a nested Graph pattern
                    if (lasttoken == Token.RIGHTCURLYBRACKET || lasttoken == Token.RIGHTBRACKET)
                    {
                        //Can Discard this if the next character is not another DOT
                        next = context.Tokens.Peek();
                        if (next.TokenType != Token.DOT)
                        {
                            if (next.TokenType != Token.RIGHTCURLYBRACKET)
                            {
                                this.TryParseTriplePatterns(context, p);
                            }
                            else
                            {
                                return;
                            }
                        }
                        else
                        {
                            throw ParserHelper.Error("A DOT Token cannot follow another DOT Token within a Graph Pattern", next);
                        }
                    }
                    else if (lasttoken == Token.SEMICOLON)
                    {
                        //Allow Trailing Semicolon
                        return;
                    }
                    else
                    {
                        throw ParserHelper.Error("A DOT Token can only be used to terminate a Triple Pattern or a Nested Graph Pattern", next);
                    }
                    break;

                default:
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered when the start of a Triple Pattern was expected", next);
            }
        }