private void TryParseMoveCommand(SparqlUpdateParserContext context)
        {
            //First an Optional SILENT keyword
            bool silent = false;
            IToken next = context.Tokens.Peek();
            if (next.TokenType == Token.SILENT)
            {
                context.Tokens.Dequeue();
                silent = true;
            }

            //Then get the Source and Destination URIs
            Uri sourceUri, destUri;
            this.TryParseTransferUris(context, out sourceUri, out destUri);

            context.CommandSet.AddCommand(new MoveCommand(sourceUri, destUri, silent));
        }
 private void TryParseUsings(SparqlUpdateParserContext context, BaseModificationCommand cmd)
 {
     foreach (KeyValuePair<Uri,bool> u in this.TryParseUsingStatements(context))
     {
         //If the Boolean flag is true then this was a USING NAMED as opposed to a USING
         if (u.Value)
         {
             cmd.AddUsingNamedUri(u.Key);
         }
         else
         {
             cmd.AddUsingUri(u.Key);
         }
     }
 }
        private void TryParseModifyCommand(SparqlUpdateParserContext context)
        {
            //Firstly we expect the URI that the modifications apply to
            Uri u = this.TryParseIriRef(context, "after a WITH keyword");

            //Now parse the INSERT/DELETE as appropriate
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType == Token.INSERT)
            {
                InsertCommand insertCmd = (InsertCommand)this.TryParseInsertCommand(context, false);
                insertCmd.GraphUri = u;
                context.CommandSet.AddCommand(insertCmd);
            }
            else if (next.TokenType == Token.DELETE)
            {
                SparqlUpdateCommand deleteCmd = this.TryParseDeleteCommand(context, false);
                if (deleteCmd is BaseModificationCommand)
                {
                    ((BaseModificationCommand)deleteCmd).GraphUri = u;
                }
                else
                {
                    throw new RdfParseException("Unexpected Command returned by TryParseDeleteCommand()");
                }
                context.CommandSet.AddCommand(deleteCmd);
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an INSERT/DELETE keyword", next);
            }
        }
        private GraphPattern TryParseModifyTemplate(SparqlUpdateParserContext context)
        {
            SparqlQueryParserContext subContext = new SparqlQueryParserContext(context.Tokens);
            subContext.Query.BaseUri = context.BaseUri;
            subContext.Query.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
            subContext.ExpressionFactories = context.ExpressionFactories;
            GraphPattern gp = context.QueryParser.TryParseGraphPattern(subContext, context.Tokens.LastTokenType != Token.LEFTCURLYBRACKET);

            //Validate that the Graph Pattern is simple
            //Check it doesn't contain anything other than Triple Patterns or if it does it just contains a single GRAPH Pattern
            if (gp.IsFiltered)
            {
                throw new RdfParseException("A FILTER Clause cannot occur in a Modify Template");
            }
            else if (gp.IsOptional)
            {
                throw new RdfParseException("An OPTIONAL Clause cannot occur in a Modify Template");
            }
            else if (gp.IsUnion)
            {
                throw new RdfParseException("A UNION Clause cannot occur in a Modify Template");
            }
            else if (gp.HasChildGraphPatterns)
            {
                if (gp.ChildGraphPatterns.All(p => p.IsGraph && !p.IsFiltered && !p.IsOptional && !p.IsUnion && !p.HasChildGraphPatterns))
                {
                    return gp;
                }
                else
                {
                    throw new RdfParseException("Nested Graph Patterns cannot occur in a Modify Template");
                }
            }
            else
            {
                return gp;
            }

        }
        private SparqlUpdateCommand TryParseInsertDataCommand(SparqlUpdateParserContext context)
        {
            InsertDataCommand cmd;

            SparqlQueryParserContext subContext = new SparqlQueryParserContext(context.Tokens);
            subContext.Query.BaseUri = context.BaseUri;
            subContext.Query.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
            subContext.ExpressionFactories = context.ExpressionFactories;
            GraphPattern gp = context.QueryParser.TryParseGraphPattern(subContext, context.Tokens.LastTokenType != Token.LEFTCURLYBRACKET);

            //Validate that the Graph Pattern is simple
            //Check it doesn't contain anything other than Triple Patterns or if it does it just contains a single GRAPH Pattern
            if (gp.IsFiltered)
            {
                throw new RdfParseException("A FILTER Clause cannot occur in a INSERT DATA Command");
            }
            else if (gp.IsOptional)
            {
                throw new RdfParseException("An OPTIONAL Clause cannot occur in a INSERT DATA Command");
            }
            else if (gp.IsUnion)
            {
                throw new RdfParseException("A UNION Clause cannot occur in a INSERT DATA Command");
            }
            else if (gp.HasChildGraphPatterns)
            {
                if (!gp.ChildGraphPatterns.All(p => p.IsGraph || (!p.IsExists && !p.IsMinus && !p.IsNotExists && !p.IsOptional && !p.IsOptional && !p.IsService && !p.IsSubQuery && !p.IsUnion)))
                {
                    throw new RdfParseException("An INSERT DATA Command may only contain a combination of Triple Patterns and GRAPH clauses");
                }
                else if (gp.ChildGraphPatterns.Any(p => p.HasChildGraphPatterns))
                {
                    throw new RdfParseException("An INSERT DATA Command may not contain nested Graph Patterns");
                }
                else if (gp.HasChildGraphPatterns && gp.TriplePatterns.Count > 0)
                {
                    cmd = new InsertDataCommand(gp);
                }
                else if (gp.ChildGraphPatterns.Count == 1 && gp.ChildGraphPatterns[0].IsGraph)
                {
                    cmd = new InsertDataCommand(gp.ChildGraphPatterns[0]);
                }
                else
                {
                    throw new RdfParseException("Nested Graph Patterns cannot occur in a INSERT DATA Command");
                }
            }
            else
            {
                //OK
                cmd = new InsertDataCommand(gp);
            }

            return cmd;
        }
        private void TryParseLoadCommand(SparqlUpdateParserContext context)
        {
            LoadCommand cmd;
            String baseUri = context.BaseUri.ToSafeString();

            //May optionally have a SILENT keyword
            bool silent = false;
            if (context.Tokens.Peek().TokenType == Token.SILENT)
            {
                silent = true;
                context.Tokens.Dequeue();
            }

            //Expect a URI which is the Source URI
            Uri sourceUri = this.TryParseIriRef(context, "to LOAD data from");

            //Then optionally an INTO GRAPH followed by a Graph URI to assign
            if (context.Tokens.Count > 0)
            {
                IToken next = context.Tokens.Peek();
                if (next.TokenType == Token.INTO)
                {
                    context.Tokens.Dequeue();
                    next = context.Tokens.Dequeue();
                    if (next.TokenType == Token.GRAPH)
                    {
                        Uri destUri = this.TryParseGraphRef(context);
                        cmd = new LoadCommand(sourceUri, destUri, silent);
                    }
                    else
                    {
                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a GRAPH keyword after the INTO keyword for a LOAD command", next);
                    }
                }
                else
                {
                    cmd = new LoadCommand(sourceUri, silent);
                }
            }
            else
            {
                cmd = new LoadCommand(sourceUri, silent);
            }
            context.CommandSet.AddCommand(cmd);
        }
        private void TryParseDropCommand(SparqlUpdateParserContext context)
        {
            bool silent = false;

            //May possibly have a SILENT Keyword
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType == Token.SILENT)
            {
                silent = true;
                next = context.Tokens.Dequeue();
            }

            //Then expect a GRAPH followed by a URI or one of the DEFAULT/NAMED/ALL keywords
            if (next.TokenType == Token.GRAPH)
            {
                Uri u = this.TryParseGraphRef(context);
                DropCommand cmd = new DropCommand(u, ClearMode.Graph, silent);
                context.CommandSet.AddCommand(cmd);
            }
            else if (next.TokenType == Token.DEFAULT)
            {
                context.CommandSet.AddCommand(new DropCommand(ClearMode.Default, silent));
            } 
            else if (next.TokenType == Token.NAMED)
            {
                context.CommandSet.AddCommand(new DropCommand(ClearMode.Named, silent));
            }
            else if (next.TokenType == Token.ALLWORD)
            {
                context.CommandSet.AddCommand(new DropCommand(ClearMode.All, silent));
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a GRAPH <URI> to specify the Graph to DROP or one of the DEFAULT/NAMED/ALL keywords", next);
            }
        }
 private Uri TryParseIriRef(SparqlUpdateParserContext context, String expected)
 {
     IToken next = context.Tokens.Dequeue();
     switch (next.TokenType)
     {
         case Token.URI:
             return new Uri(Tools.ResolveUri(next.Value, context.BaseUri.ToSafeString()));
         case Token.QNAME:
             return new Uri(Tools.ResolveQName(next.Value, context.NamespaceMap, context.BaseUri));
         default:
             throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a URI/QName Token " + expected, next);
     }
 }
        private void TryParsePrefixDeclaration(SparqlUpdateParserContext context)
        {
            //Get the next Two Tokens which should be a Prefix and a Uri
            IToken prefix = context.Tokens.Dequeue();
            IToken uri = context.Tokens.Dequeue();

            if (prefix.TokenType == Token.PREFIX)
            {
                if (uri.TokenType == Token.URI)
                {
                    String baseUri = (context.BaseUri != null) ? context.BaseUri.ToString() : String.Empty;
                    Uri u = new Uri(Tools.ResolveUri(uri.Value, baseUri));
                    if (prefix.Value.Length == 1)
                    {
                        //Defining prefix for Default Namespace
                        context.NamespaceMap.AddNamespace(String.Empty, u);
                        context.CommandSet.NamespaceMap.AddNamespace(String.Empty, u);
                    }
                    else
                    {
                        //Defining prefix for some other Namespace
                        context.NamespaceMap.AddNamespace(prefix.Value.Substring(0, prefix.Value.Length - 1), u);
                        context.CommandSet.NamespaceMap.AddNamespace(prefix.Value.Substring(0, prefix.Value.Length - 1), u);
                    }
                }
                else
                {
                    throw ParserHelper.Error("Expected a URI Token to follow a Prefix Token to follow the PREFIX Verb in an Update", uri);
                }
            }
            else
            {
                throw ParserHelper.Error("Expected a Prefix Token to follow the PREFIX Verb in an Update", prefix);
            }
        }
        private void TryParseCreateCommand(SparqlUpdateParserContext context)
        {
            bool silent = false;

            //May possibly have a SILENT Keyword
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType == Token.SILENT)
            {
                silent = true;
                next = context.Tokens.Dequeue();
            }

            //Followed by a mandatory GRAPH Keyword
            if (next.TokenType != Token.GRAPH)
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a GRAPH Keyword as part of the CREATE command", next);
            }

            //Then MUST have a URI
            Uri u = this.TryParseGraphRef(context);
            CreateCommand cmd = new CreateCommand(u, silent);
            context.CommandSet.AddCommand(cmd);
        }
 private void TryParseBaseDeclaration(SparqlUpdateParserContext context)
 {
     //Get the next Token which should be a Uri Token
     IToken next = context.Tokens.Dequeue();
     if (next.TokenType == Token.URI)
     {
         context.BaseUri = new Uri(next.Value);
         context.CommandSet.BaseUri = context.BaseUri;
         context.QueryParser.DefaultBaseUri = context.BaseUri;
         context.ExpressionParser.BaseUri = context.BaseUri;
     }
     else
     {
         throw ParserHelper.Error("Expected a URI Token to follow the BASE Verb in an Update", next);
     }
 }
        private SparqlUpdateCommandSet ParseInternal(SparqlUpdateParserContext context)
        {
            //Set up the Context appropriately
            context.BaseUri = this.DefaultBaseUri;
            context.QueryParser.ExpressionFactories = context.ExpressionFactories;
            context.QueryParser.DefaultBaseUri = this.DefaultBaseUri;
            context.ExpressionParser.BaseUri = this.DefaultBaseUri;
            context.ExpressionParser.NamespaceMap = context.NamespaceMap;
            context.ExpressionParser.QueryParser = context.QueryParser;
            context.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
            context.Tokens.InitialiseBuffer();

            IToken next;
            bool commandParsed = false;
            do
            {
                next = context.Tokens.Dequeue();
                switch (next.TokenType)
                {
                    case Token.BOF:
                    case Token.COMMENT:
                        //Discardable Tokens
                        break;
                    case Token.EOF:
                        if (next.StartLine == 1 && next.StartPosition == 1)
                        {
                            throw new RdfParseException("Empty SPARQL Updates are not permitted");
                        }
                        break;

                    case Token.BASEDIRECTIVE:
                        this.TryParseBaseDeclaration(context);
                        break;
                    case Token.PREFIXDIRECTIVE:
                        this.TryParsePrefixDeclaration(context);
                        break;

                    case Token.ADD:
                        this.TryParseAddCommand(context);
                        commandParsed = true;
                        break;

                    case Token.CLEAR:
                        this.TryParseClearCommand(context);
                        commandParsed = true;
                        break;

                    case Token.COPY:
                        this.TryParseCopyCommand(context);
                        commandParsed = true;
                        break;

                    case Token.CREATE:
                        this.TryParseCreateCommand(context);
                        commandParsed = true;
                        break;

                    case Token.DROP:
                        this.TryParseDropCommand(context);
                        commandParsed = true;
                        break;

                    case Token.DELETE:
                        context.CommandSet.AddCommand(this.TryParseDeleteCommand(context, true));
                        commandParsed = true;
                        break;

                    case Token.INSERT:
                        context.CommandSet.AddCommand(this.TryParseInsertCommand(context, true));
                        commandParsed = true;
                        break;

                    case Token.LOAD:
                        this.TryParseLoadCommand(context);
                        commandParsed = true;
                        break;

                    case Token.MOVE:
                        this.TryParseMoveCommand(context);
                        commandParsed = true;
                        break;

                    case Token.WITH:
                        this.TryParseModifyCommand(context);
                        commandParsed = true;
                        break;

                    default:
                        throw ParserHelper.Error("Unexpected Token encountered", next);
                }

                if (commandParsed)
                {
                    //After a Command we expect to see either a separator or EOF
                    next = context.Tokens.Dequeue();
                    if (next.TokenType != Token.SEMICOLON && next.TokenType != Token.EOF)
                    {
                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a semicolon separator or EOF after a command", next);
                    }

                    commandParsed = false;
                }

            } while (next.TokenType != Token.EOF);

            //Optimise the Command Set before returning it
            context.CommandSet.Optimise();
            return context.CommandSet;
        }
        /// <summary>
        /// Parses a SPARQL Update Command Set from the input
        /// </summary>
        /// <param name="input">Input</param>
        /// <returns></returns>
        public SparqlUpdateCommandSet Parse(TextReader input)
        {
            if (input == null) throw new RdfParseException("Cannot parse SPARQL Update Commands from a null TextReader");

            try
            {
                //Start the actual parsing
                SparqlUpdateParserContext context = new SparqlUpdateParserContext(new SparqlTokeniser(input, SparqlQuerySyntax.Sparql_1_1));
                return this.ParseInternal(context);
            }
            catch
            {
                throw;
            }
            finally
            {
                try
                {
                    input.Close();
                }
                catch
                {
                    //No catch actions just trying to clean up the stream
                }
            }
        }
        private IEnumerable<KeyValuePair<Uri,bool>> TryParseUsingStatements(SparqlUpdateParserContext context)
        {
            if (context.Tokens.Count > 0)
            {
                String baseUri = (context.BaseUri == null) ? String.Empty : context.BaseUri.ToString();
                IToken next = context.Tokens.Peek();
                bool named = false;

                //While we can see USINGs we'll keep returning USING URIs
                do
                {
                    if (context.Tokens.LastTokenType != Token.USING) context.Tokens.Dequeue();
                    next = context.Tokens.Peek();

                    if (next.TokenType == Token.NAMED)
                    {
                        context.Tokens.Dequeue();
                        next = context.Tokens.Peek();
                        named = true;
                    }
                    if (next.TokenType == Token.URI || next.TokenType == Token.QNAME)
                    {
                        //Yield the URI
                        Uri u = this.TryParseIriRef(context, " as part of a USING clause");
                        yield return new KeyValuePair<Uri, bool>(u, named);
                    }
                    else
                    {
                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a URI as part of a USING statement", next);
                    }

                    //Peek at the next thing in case it's a further USING
                    next = context.Tokens.Peek();
                } while (next.TokenType == Token.USING);
            }
            else
            {
                yield break;
            }
        }
        private SparqlUpdateCommand TryParseInsertCommand(SparqlUpdateParserContext context, bool allowData)
        {
            List<Uri> usings = new List<Uri>();
            List<Uri> usingNamed = new List<Uri>();
            IToken next = context.Tokens.Dequeue();
            if (allowData)
            {
                //We are allowed to have an INSERT DATA command here so check for it
                if (next.TokenType == Token.DATA) return this.TryParseInsertDataCommand(context);
            }
            else
            {
                if (next.TokenType == Token.DATA) throw ParserHelper.Error("The DATA keyword is not permitted here as this INSERT command forms part of a modification command", next);
            }

            //Get the Modification Template
            GraphPattern insertions = this.TryParseModifyTemplate(context);

            //Then we expect a WHERE keyword
            next = context.Tokens.Dequeue();
            if (next.TokenType == Token.USING)
            {
                foreach (KeyValuePair<Uri, bool> kvp in this.TryParseUsingStatements(context))
                {
                    if (kvp.Value)
                    {
                        usingNamed.Add(kvp.Key);
                    }
                    else
                    {
                        usings.Add(kvp.Key);
                    }
                }
                next = context.Tokens.Dequeue();
            }
            if (next.TokenType != Token.WHERE) throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a WHERE keyword as part of a INSERT command", next);
            
            //Now parse the WHERE pattern
            SparqlQueryParserContext subContext = new SparqlQueryParserContext(context.Tokens);
            subContext.Query.BaseUri = context.BaseUri;
            subContext.Query.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.NamespaceMap = context.NamespaceMap;
            subContext.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
            subContext.ExpressionFactories = context.ExpressionFactories;
            GraphPattern where = context.QueryParser.TryParseGraphPattern(subContext, context.Tokens.LastTokenType != Token.LEFTCURLYBRACKET);

            //And finally return the command
            InsertCommand cmd = new InsertCommand(insertions, where);
            usings.ForEach(u => cmd.AddUsingUri(u));
            usingNamed.ForEach(u => cmd.AddUsingNamedUri(u));
            return cmd;
        }
        private void TryParseTransferUris(SparqlUpdateParserContext context, out Uri sourceUri, out Uri destUri)
        {
            IToken next = context.Tokens.Dequeue();
            sourceUri = destUri = null;

            //Parse the Source Graph URI
            if (next.TokenType == Token.GRAPH)
            {
                next = context.Tokens.Peek();
                if (next.TokenType == Token.URI || next.TokenType == Token.QNAME)
                {
                    sourceUri = this.TryParseIriRef(context, " to indicate the Source Graph for a Transfer (ADD/COPY/MOVE) command");
                }
                else
                {
                    ParserHelper.Error("Unexpected Token '" + next.GetType().Name + "' encountered, expected a URI/QName after a GRAPH keyword to specify the URI of the Source Graph for a Transfer (ADD/COPY/MOVE) Command", next);
                }
            }
            else if (next.TokenType == Token.DEFAULT)
            {
                sourceUri = null;
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().Name + "' encountered, expected a GRAPH/DEFAULT keyword to indicate the Source Graph for a Transfer (ADD/COPY/MOVE) Command", next);
            }

            //Then get the TO keyword
            next = context.Tokens.Dequeue();
            if (next.TokenType != Token.TO) throw ParserHelper.Error("Unexpected Token '" + next.GetType().Name + "' encountered, expected a TO Keyword after the Source Graph specifier", next);

            next = context.Tokens.Dequeue();

            //Parse the Destination Graph URI
            if (next.TokenType == Token.GRAPH)
            {
                next = context.Tokens.Peek();
                if (next.TokenType == Token.URI || next.TokenType == Token.QNAME)
                {
                    destUri = this.TryParseIriRef(context, " to indicate the Destination Graph for a Transfer (ADD/COPY/MOVE) command");
                }
                else
                {
                    ParserHelper.Error("Unexpected Token '" + next.GetType().Name + "' encountered, expected a URI/QName after a GRAPH keyword to specify the URI of the Destination Graph for a Transfer (ADD/COPY/MOVE) Command", next);
                }
            }
            else if (next.TokenType == Token.DEFAULT)
            {
                destUri = null;
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().Name + "' encountered, expected a GRAPH/DEFAULT keyword to indicate the Destination Graph for a Transfer (ADD/COPY/MOVE) Command", next);
            }
        }
 private Uri TryParseGraphRef(SparqlUpdateParserContext context)
 {
     return this.TryParseIriRef(context, "after a GRAPH keyword");
 }