private void TryParseUnionClause(SparqlQueryParserContext context, GraphPattern p) { //Create a new Pattern which will hold the UNION GraphPattern union = new GraphPattern(); union.IsUnion = true; //Add the Last Child Pattern of the Parent as that is the start of the UNION GraphPattern lastchild = p.LastChildPattern(); if (lastchild.IsSimplifiable) { union.AddGraphPattern(lastchild.LastChildPattern()); } else { union.AddGraphPattern(lastchild); } GraphPattern child = this.TryParseGraphPattern(context, true); union.AddGraphPattern(child); //Check for multiple IToken next = context.Tokens.Peek(); while (next.TokenType == Token.UNION) { context.Tokens.Dequeue(); union.AddGraphPattern(this.TryParseGraphPattern(context, true)); next = context.Tokens.Peek(); } p.AddGraphPattern(union); }
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); } }