/// <summary>
 /// Creates a new Bound Filter
 /// </summary>
 /// <param name="varTerm">Variable Expression</param>
 public BoundFilter(VariableExpressionTerm varTerm)
     : base(varTerm) { }
        private ISparqlExpression TryParseBuiltInCall(Queue<IToken> tokens)
        {
            IToken next = tokens.Dequeue();
            bool comma = false, first = true;
            List<ISparqlExpression> args;
            ISparqlExpression strExpr;

            switch (next.TokenType)
            {
                case Token.ABS:
                    return new AbsFunction(this.TryParseBrackettedExpression(tokens));
                case Token.BNODE:
                    return new BNodeFunction(this.TryParseBrackettedExpression(tokens));                

                case Token.BOUND:
                    //Expect a Left Bracket, Variable and then a Right Bracket
                    next = tokens.Dequeue();
                    if (next.TokenType == Token.LEFTBRACKET)
                    {
                        next = tokens.Dequeue();
                        if (next.TokenType == Token.VARIABLE)
                        {
                            VariableExpressionTerm varExpr = new VariableExpressionTerm(next.Value);
                            next = tokens.Dequeue();
                            if (next.TokenType == Token.RIGHTBRACKET)
                            {
                                return new BoundFunction(varExpr);
                            }
                            else
                            {
                                throw Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, a Right Bracket to end a BOUND function call was expected",next);
                            }
                        }
                        else
                        {
                            throw Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, a Variable Token for a BOUND function call was expected", next);
                        }
                    }
                    else
                    {
                        throw Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, a Left Bracket to start a BOUND function call was expected", next);
                    }

                case Token.CEIL:
                    return new CeilFunction(this.TryParseBrackettedExpression(tokens));

                case Token.COALESCE:
                    //Get as many argument expressions as we can
                    args = new List<ISparqlExpression>();
                    do
                    {
                        args.Add(this.TryParseBrackettedExpression(tokens, first, out comma));
                        first = false;
                    } while (comma);

                    return new CoalesceFunction(args);

                case Token.CONCAT:
                    //Get as many argument expressions as we can
                    args = new List<ISparqlExpression>();
                    do
                    {
                        args.Add(this.TryParseBrackettedExpression(tokens, first, out comma));
                        first = false;
                    } while (comma);

                    return new ConcatFunction(args);

                case Token.CONTAINS:
                    return new ContainsFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.DATATYPEFUNC:
                    return new DataTypeFunction(this.TryParseBrackettedExpression(tokens));
                case Token.DAY:
                    return new DayFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ENCODEFORURI:
                    return new EncodeForUriFunction(this.TryParseBrackettedExpression(tokens));
                case Token.FLOOR:
                    return new FloorFunction(this.TryParseBrackettedExpression(tokens));
                case Token.HOURS:
                    return new HoursFunction(this.TryParseBrackettedExpression(tokens));
                case Token.IF:
                    return new IfElseFunction(this.TryParseBrackettedExpression(tokens, true, out comma), this.TryParseBrackettedExpression(tokens, false, out comma), this.TryParseBrackettedExpression(tokens, false, out comma));
                case Token.IRI:
                case Token.URIFUNC:
                    return new IriFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ISBLANK:
                    return new IsBlankFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ISIRI:
                    return new IsIriFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ISLITERAL:
                    return new IsLiteralFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ISNUMERIC:
                    return new IsNumericFunction(this.TryParseBrackettedExpression(tokens));
                case Token.ISURI:
                    return new IsUriFunction(this.TryParseBrackettedExpression(tokens));
                case Token.LANG:
                    return new LangFunction(this.TryParseBrackettedExpression(tokens));
                case Token.LANGMATCHES:
                    return new LangMatchesFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.LCASE:
                    return new LCaseFunction(this.TryParseBrackettedExpression(tokens));
                case Token.MD5:
                    return new MD5HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.MINUTES:
                    return new MinutesFunction(this.TryParseBrackettedExpression(tokens));
                case Token.MONTH:
                    return new MonthFunction(this.TryParseBrackettedExpression(tokens));

                case Token.NOW:
                    //Expect a () after the Keyword Token
                    next = tokens.Dequeue();
                    if (next.TokenType != Token.LEFTBRACKET) throw Error("Expected a Left Bracket after a NOW keyword to call the NOW() function", next);
                    next = tokens.Dequeue();
                    if (next.TokenType != Token.RIGHTBRACKET) throw Error("Expected a Right Bracket after NOW( since the NOW() function does not take any arguments", next);
                    return new NowFunction();

                case Token.RAND:
                    //Expect a () after the Keyword Token
                    next = tokens.Dequeue();
                    if (next.TokenType != Token.LEFTBRACKET) throw Error("Expected a Left Bracket after a RAND keyword to call the RAND() function", next);
                    next = tokens.Dequeue();
                    if (next.TokenType != Token.RIGHTBRACKET) throw Error("Expected a Right Bracket after RAND( since the RAND() function does not take any arguments", next);
                    return new RandFunction();

                case Token.REGEX:
                    return this.TryParseRegexExpression(tokens);
                case Token.REPLACE:
                    //REPLACE may have 3/4 arguments
                    strExpr = this.TryParseBrackettedExpression(tokens);
                    ISparqlExpression patternExpr = this.TryParseBrackettedExpression(tokens, false);
                    ISparqlExpression replaceExpr = this.TryParseBrackettedExpression(tokens, false, out comma);
                    if (comma)
                    {
                        ISparqlExpression opsExpr = this.TryParseBrackettedExpression(tokens, false);
                        return new ReplaceFunction(strExpr, patternExpr, replaceExpr, opsExpr);
                    }
                    else
                    {
                        return new ReplaceFunction(strExpr, patternExpr, replaceExpr);
                    }
                case Token.ROUND:
                    return new RoundFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SAMETERM:
                    return new SameTermFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.SECONDS:
                    return new SecondsFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SHA1:
                    return new Sha1HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SHA224:
                    return new Sha224HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SHA256:
                    return new Sha256HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SHA384:
                    return new Sha384HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.SHA512:
                    return new Sha512HashFunction(this.TryParseBrackettedExpression(tokens));
                case Token.STR:
                    return new StrFunction(this.TryParseBrackettedExpression(tokens));
                case Token.STRAFTER:
                    return new StrAfterFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.STRBEFORE:
                    return new StrBeforeFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.STRDT:
                    return new StrDtFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.STRENDS:
                    return new StrEndsFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.STRLANG:
                    return new StrLangFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));
                case Token.STRLEN:
                    return new StrLenFunction(this.TryParseBrackettedExpression(tokens));
                case Token.STRSTARTS:
                    return new StrStartsFunction(this.TryParseBrackettedExpression(tokens), this.TryParseBrackettedExpression(tokens, false));

                case Token.SUBSTR:
                    //SUBSTR may have 2/3 arguments
                    strExpr = this.TryParseBrackettedExpression(tokens);
                    ISparqlExpression startExpr = this.TryParseBrackettedExpression(tokens, false, out comma);
                    if (comma)
                    {
                        ISparqlExpression lengthExpr = this.TryParseBrackettedExpression(tokens, false);
                        return new SubStrFunction(strExpr, startExpr, lengthExpr);
                    }
                    else
                    {
                        return new SubStrFunction(strExpr, startExpr);
                    }

                case Token.TIMEZONE:
                    return new TimezoneFunction(this.TryParseBrackettedExpression(tokens));
                case Token.TZ:
                    return new TZFunction(this.TryParseBrackettedExpression(tokens));
                case Token.UCASE:
                    return new UCaseFunction(this.TryParseBrackettedExpression(tokens));
                case Token.YEAR:
                    return new YearFunction(this.TryParseBrackettedExpression(tokens));

                case Token.EXISTS:
                case Token.NOTEXISTS:
                    if (this._syntax == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("EXISTS/NOT EXISTS clauses are not supported in SPARQL 1.0");
                    if (this._parser == null) throw new RdfParseException("Unable to parse an EXISTS/NOT EXISTS as there is no Query Parser to call into");

                    //Gather Tokens for the Pattern
                    NonTokenisedTokenQueue temptokens = new NonTokenisedTokenQueue();
                    int openbrackets = 0;
                    bool mustExist = (next.TokenType == Token.EXISTS);
                    do
                    {
                        if (tokens.Count == 0) throw new RdfParseException("Unexpected end of Tokens while trying to parse an EXISTS/NOT EXISTS function");

                        next = tokens.Dequeue();
                        if (next.TokenType == Token.LEFTCURLYBRACKET)
                        {
                            openbrackets++;
                        }
                        else if (next.TokenType == Token.RIGHTCURLYBRACKET)
                        {
                            openbrackets--;
                        }
                        temptokens.Enqueue(next);
                    } while (openbrackets > 0);

                    //Call back into the Query Parser to try and Parse the Graph Pattern for the Function
                    SparqlQueryParserContext tempcontext = new SparqlQueryParserContext(temptokens);
                    tempcontext.Query.NamespaceMap.Import(this._nsmapper);
                    tempcontext.Query.BaseUri = this._baseUri;
                    return new ExistsFunction(this._parser.TryParseGraphPattern(tempcontext, true), mustExist);

                default:
                    throw Error("Unexpected Token '" + next.GetType().ToString() + "' encountered while trying to parse a Built-in Function call", next);
            }
        }
 /// <summary>
 /// Creates a new MEDIAN Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 public MedianAggregate(VariableExpressionTerm expr)
     : this(expr, false) { }
 /// <summary>
 /// Creates a new MEDIAN Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 /// <param name="distinct">Whether a DISTINCT modifier applies</param>
 public MedianAggregate(VariableExpressionTerm expr, bool distinct)
     : base(expr, distinct)
 {
     this._varname = expr.ToString().Substring(1);
 }
 /// <summary>
 /// Creates a new NMIN Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 public NumericMinAggregate(VariableExpressionTerm expr)
     : this(expr, false) { }
 /// <summary>
 /// Creates a new MODE Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 public ModeAggregate(VariableExpressionTerm expr)
     : base(expr, false) { }
 /// <summary>
 /// Creates a new AVG Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 public AverageAggregate(VariableExpressionTerm expr)
     : this(expr, false) { }
 /// <summary>
 /// Creates a new COUNT(DISTINCT ?x) Aggregate
 /// </summary>
 /// <param name="expr">Variable Expression</param>
 public CountDistinctAggregate(VariableExpressionTerm expr)
     : base(expr)
 {
     this._varname = expr.ToString().Substring(1);
 }
        private void TryParseLetAssignment(SparqlQueryParserContext context, GraphPattern p)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("LET assignment is not supported in SPARQL 1.0");
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_1) throw new RdfParseException("LET assignment is not supported in SPARQL 1.1 - use BIND assignment instead");

            IToken variable;
            ISparqlExpression expr;

            //Firstly we expect an opening bracket, a variable and then an assignment operator
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType == Token.LEFTBRACKET)
            {
                next = context.Tokens.Dequeue();
                if (next.TokenType == Token.VARIABLE)
                {
                    variable = next;
                    context.Query.AddVariable(variable.Value, false);
                    next = context.Tokens.Dequeue();
                    if (next.TokenType == Token.ASSIGNMENT)
                    {
                        //See if there is a valid expression for the right hand side of the assignment
                        next = context.Tokens.Peek();
                        switch (next.TokenType)
                        {
                            case Token.ABS:
                            case Token.BNODE:
                            case Token.BOUND:
                            case Token.CEIL:
                            case Token.COALESCE:
                            case Token.CONCAT:
                            case Token.DATATYPEFUNC:
                            case Token.DAY:
                            case Token.ENCODEFORURI:
                            case Token.EXISTS:
                            case Token.FLOOR:
                            case Token.HOURS:
                            case Token.IF:
                            case Token.IRI:
                            case Token.ISBLANK:
                            case Token.ISIRI:
                            case Token.ISLITERAL:
                            case Token.ISNUMERIC:
                            case Token.ISURI:
                            case Token.LANG:
                            case Token.LANGMATCHES:
                            case Token.LCASE:
                            case Token.MINUTES:
                            case Token.MONTH:
                            case Token.NOTEXISTS:
                            case Token.NOW:
                            case Token.RAND:
                            case Token.REGEX:
                            case Token.ROUND:
                            case Token.SAMETERM:
                            case Token.SECONDS:
                            case Token.SHA1:
                            case Token.SHA224:
                            case Token.SHA256:
                            case Token.SHA384:
                            case Token.SHA512:
                            case Token.STR:
                            case Token.CONTAINS:
                            case Token.STRDT:
                            case Token.STRENDS:
                            case Token.STRLANG:
                            case Token.STRLEN:
                            case Token.STRSTARTS:
                            case Token.SUBSTR:
                            case Token.TIMEZONE:
                            case Token.TZ:
                            case Token.UCASE:
                            case Token.URIFUNC:
                            case Token.YEAR:
                            case Token.URI:
                            case Token.QNAME:
                                expr = this.TryParseFunctionExpression(context);
                                break;
                            case Token.LEFTBRACKET:
                                context.Tokens.Dequeue();
                                expr = this.TryParseExpression(context, false);
                                break;
                            case Token.VARIABLE:
                                context.Tokens.Dequeue();
                                expr = new VariableExpressionTerm(next.Value);
                                break;
                            default:
                                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Token which was valid as the start of an expression for the right hand side of a LET assignment", next);
                        }

                        //Finally expect a Right Bracket to terminate the LET
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.RIGHTBRACKET)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Right Bracket to terminate the LET assignment", next);
                        }
                        
                        //Create a Let Pattern and add to the Query appropriately
                        LetPattern let = new LetPattern(variable.Value.Substring(1), expr);
                        if (Options.QueryOptimisation)
                        {
                            p.AddAssignment(let);
                        }
                        else
                        {
                            //When Optimisation is turned off we'll just stick the Let in the Triples Pattern where it occurs
                            //since we're not going to do any Triple Pattern ordering, Assignment or FILTER placement
                            p.AddTriplePattern(let);
                        }
                    }
                    else
                    {
                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an Assignment operator as part of a LET assignment", next);
                    }
                }
                else
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Variable as the first item in a LET assignment", next);
                }
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Left Bracket to start a LET assignment after a LET Keyword", next);
            }
        }