/// <summary>
 /// Creates a new SPARQL Query Parser Context for parsing sub-queries.
 /// </summary>
 /// <param name="parent">Parent Query Parser Context.</param>
 /// <param name="tokens">Tokens that need parsing to form a subquery.</param>
 protected internal SparqlQueryParserContext(SparqlQueryParserContext parent, ITokenQueue tokens)
     : base(new NullHandler(), null)
 {
     _traceParsing          = parent.TraceParsing;
     _traceTokeniser        = parent.TraceTokeniser;
     _queue                 = tokens;
     _subqueryMode          = true;
     _query                 = new SparqlQuery(true);
     _factories             = parent.ExpressionFactories;
     _syntax                = parent.SyntaxMode;
     _exprParser.SyntaxMode = _syntax;
 }
 /// <summary>
 /// Creates a new SPARQL Query Parser Context for parsing sub-queries
 /// </summary>
 /// <param name="parent">Parent Query Parser Context</param>
 /// <param name="tokens">Tokens that need parsing to form a subquery</param>
 protected internal SparqlQueryParserContext(SparqlQueryParserContext parent, ITokenQueue tokens)
     : base(new NullHandler(), null)
 {
     this._traceParsing = parent.TraceParsing;
     this._traceTokeniser = parent.TraceTokeniser;
     this._queue = tokens;
     this._subqueryMode = true;
     this._query = new SparqlQuery(true);
     this._factories = parent.ExpressionFactories;
     this._syntax = parent.SyntaxMode;
     this._exprParser.SyntaxMode = this._syntax;
 }
Пример #3
0
        public ISparqlPath Parse(SparqlQueryParserContext context, IToken first)
        {
            //Need to gather up all the Tokens which make up the path
            int openBrackets = 0;
            Queue<IToken> tokens = new Queue<IToken>();
            IToken next;
            LastPathItemType lastItem = LastPathItemType.None;
            int lastSequencer = -1;

            //Add the first token and set the initial last item type
            tokens.Enqueue(first);
            switch (first.TokenType)
            {
                case Token.LEFTBRACKET:
                    openBrackets = 1;
                    lastItem = LastPathItemType.Predicate;
                    break;
                case Token.QNAME:
                case Token.URI:
                case Token.KEYWORDA:
                    lastItem = LastPathItemType.Predicate;
                    break;
                case Token.HAT:
                    lastItem = LastPathItemType.Sequencer;
                    break;
                case Token.NEGATION:
                    lastItem = LastPathItemType.Negation;
                    break;
                default:
                    throw new RdfParseException("Unexpected Token '" + first.GetType().ToString() + "' encountered, this is not valid as the start of a property path");
            }

            while (true)
            {
                next = context.Tokens.Peek();
                if (openBrackets > 0)
                {
                    context.Tokens.Dequeue();
                    tokens.Enqueue(next);

                    if (next.TokenType == Token.RIGHTBRACKET)
                    {
                        openBrackets--;
                        //Groups are considered predicates for purposes of last item
                        lastItem = LastPathItemType.Predicate;
                    }
                }
                else
                {
                    switch (next.TokenType)
                    {
                        case Token.LEFTBRACKET:
                            //Path Group

                            if (lastItem == LastPathItemType.Predicate || lastItem == LastPathItemType.Modifier)
                            {
                                //If it follows a Predicate/Modifier then this is likely a collection as the object of a
                                //Triple pattern so we stop
                                lastItem = LastPathItemType.End;
                            }
                            else if (lastItem == LastPathItemType.Sequencer || lastItem == LastPathItemType.Negation)
                            {
                                //This is a new Path Group if it follows a sequencer/negation
                                openBrackets++;
                                context.Tokens.Dequeue();
                                tokens.Enqueue(next);
                                lastItem = LastPathItemType.Predicate;
                            }
                            else
                            {
                                throw new RdfParseException("Path Groups can only follow path sequencing tokens", next);
                            }
                                break;

                        case Token.LEFTCURLYBRACKET:
                            //Explicit cardinality modifiers

                            if (lastItem != LastPathItemType.Predicate)
                            {
                                throw new RdfParseException("Cardinality Modifiers can only follow Predicates/Path Groups", next);
                            }

                            //Add the opening { to the tokens
                            context.Tokens.Dequeue();
                            tokens.Enqueue(next);
                            next = context.Tokens.Peek();

                            //Grab everything up to the next }
                            while (next.TokenType != Token.RIGHTCURLYBRACKET)
                            {
                                //If we see another { this is an error
                                if (next.TokenType == Token.LEFTCURLYBRACKET)
                                {
                                    throw new RdfParseException("Nested Cardinality Modifiers for Paths are not permitted", next);
                                }

                                context.Tokens.Dequeue();
                                tokens.Enqueue(next);
                                next = context.Tokens.Peek();
                            }
                            //Add the trailing } to the tokens
                            context.Tokens.Dequeue();
                            tokens.Enqueue(next);
                            lastItem = LastPathItemType.Modifier;
                            break;

                        case Token.PLUS:
                        case Token.QUESTION:
                        case Token.MULTIPLY:
                            //Other Cardinality modifiers are permitted

                            if (lastItem != LastPathItemType.Predicate)
                            {
                                throw new RdfParseException("Cardinality Modifiers can only follow Predicates/Path Groups");
                            }

                            context.Tokens.Dequeue();
                            tokens.Enqueue(next);
                            lastItem = LastPathItemType.Modifier;
                            break;

                        case Token.BITWISEOR:
                        case Token.DIVIDE:
                        case Token.HAT:
                            //Path sequencing

                            if (lastItem != LastPathItemType.Predicate && lastItem != LastPathItemType.Modifier)
                            {
                                if (lastItem == LastPathItemType.Sequencer && next.TokenType == Token.HAT && (lastSequencer == Token.DIVIDE || lastSequencer == Token.BITWISEOR))
                                {
                                    // / ^ or | ^ is a valid sequencing
                                }
                                else
                                {
                                    throw new RdfParseException("Path sequencing tokens can only follow Predicates/Path Groups", next);
                                }
                            }

                            context.Tokens.Dequeue();
                            tokens.Enqueue(next);
                            lastItem = LastPathItemType.Sequencer;
                            lastSequencer = next.TokenType;
                            break;

                        case Token.QNAME:
                        case Token.URI:
                        case Token.KEYWORDA:
                            //Predicates

                            if (lastItem != LastPathItemType.None && lastItem != LastPathItemType.Sequencer && lastItem != LastPathItemType.Negation)
                            {
                                //This appears to be the end of the path since we've encountered something that could be
                                //an Object
                                lastItem = LastPathItemType.End;
                            }
                            else
                            {
                                context.Tokens.Dequeue();
                                tokens.Enqueue(next);
                                lastItem = LastPathItemType.Predicate;
                            }
                            break;

                        case Token.NEGATION:
                            if (lastItem == LastPathItemType.Sequencer)
                            {
                                context.Tokens.Dequeue();
                                tokens.Enqueue(next);
                                lastItem = LastPathItemType.Negation;
                            }
                            else
                            {
                                throw new RdfParseException("Negated Property Sets can only follow path sequencing tokens", next);
                            }
                            break;

                        default:
                            if (lastItem != LastPathItemType.None && lastItem != LastPathItemType.Sequencer)
                            {
                                //Appears to be the end of the path since we've encountered an unexpected token after seeing
                                //a Predicate
                                lastItem = LastPathItemType.End;
                            }
                            else
                            {
                                throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encounted, this is not a valid token for a Path", next);
                            }
                            break;
                    }

                    if (lastItem == LastPathItemType.End) break;
                }
            }

            ISparqlPath path = this.TryParsePath(context, tokens);
            return path;
        }
Пример #4
0
        private ISparqlPath TryParsePathPrimary(SparqlQueryParserContext context, Queue<IToken> tokens)
        {
            IToken next = tokens.Dequeue();
            ISparqlPath path;
            switch (next.TokenType)
            {
                case Token.URI:
                case Token.QNAME:
                    path =  new Property(new UriNode(null, UriFactory.Create(Tools.ResolveUriOrQName(next, context.Query.NamespaceMap, context.Query.BaseUri))));
                    break;

                case Token.KEYWORDA:
                    path =  new Property(new UriNode(null, UriFactory.Create(RdfSpecsHelper.RdfType)));
                    break;

                case Token.LEFTBRACKET:
                    Queue<IToken> subtokens = new Queue<IToken>();
                    int openBrackets = 1;
                    do {
                        next = tokens.Dequeue();
                        if (next.TokenType == Token.LEFTBRACKET)
                        {
                            openBrackets++;
                        }
                        else if (next.TokenType == Token.RIGHTBRACKET)
                        {
                            openBrackets--;
                        }

                        if (openBrackets > 0) subtokens.Enqueue(next);
                    } while (openBrackets > 0);

                    path = this.TryParsePath(context, subtokens);
                    break;

                case Token.NEGATION:
                    path = this.TryParseNegatedPropertySet(context, tokens);
                    break;

                default:
                    throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a URI/QName, the 'a' keyword or the start of a group path expression", next);
            }

            //See if there's a Path Modifier
            if (tokens.Count > 0)
            {
                next = tokens.Peek();
                switch (next.TokenType)
                {
                    case Token.MULTIPLY:
                    case Token.PLUS:
                    case Token.QUESTION:
                    case Token.LEFTCURLYBRACKET:
                        path = this.TryParsePathMod(context, tokens, path);
                        break;
                }
            }

            return path;
        }
Пример #5
0
 private ISparqlPath TryParsePathMod(SparqlQueryParserContext context, Queue<IToken> tokens, ISparqlPath path)
 {
     IToken next = tokens.Dequeue();
     switch (next.TokenType)
     {
         case Token.MULTIPLY:
             return new ZeroOrMore(path);
         case Token.QUESTION:
             return new ZeroOrOne(path);
         case Token.PLUS:
             return new OneOrMore(path);
         case Token.LEFTCURLYBRACKET:
             next = tokens.Dequeue();
             int min, max;
             if (next.TokenType == Token.PLAINLITERAL)
             {
                 if (Int32.TryParse(next.Value, out min))
                 {
                     if (min < 0) throw new RdfParseException("Cannot specify the minimum cardinality of a path as less than zero", next);
                     next = tokens.Dequeue();
                     if (next.TokenType == Token.COMMA)
                     {
                         next = tokens.Dequeue();
                         if (next.TokenType == Token.PLAINLITERAL)
                         {
                             if (Int32.TryParse(next.Value, out max))
                             {
                                 if (max < min) throw new RdfParseException("Cannot specify the maximum cardinality of a path as less than the minimum", next);
                                 next = tokens.Dequeue();
                                 if (next.TokenType != Token.RIGHTCURLYBRACKET) throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a } to terminate a Path Cardinality modifier", next);
                                 if (min == max)
                                 {
                                     return new FixedCardinality(path, min);
                                 }
                                 else
                                 {
                                     return new NToM(path, min, max);
                                 }
                             }
                             else
                             {
                                 throw new RdfParseException("The value '" + next.Value + "' is not valid for use as a Path Cardinality modifier", next);
                             }
                         }
                         else if (next.TokenType == Token.RIGHTCURLYBRACKET)
                         {
                             if (min == 0)
                             {
                                 return new ZeroOrMore(path);
                             }
                             else if (min == 1)
                             {
                                 return new OneOrMore(path);
                             }
                             else
                             {
                                 return new NOrMore(path, min);
                             }
                         }
                         else
                         {
                             throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an Integer Plain Literal as part of a Path Cardinality modifier", next);
                         }
                     }
                     else if (next.TokenType == Token.RIGHTCURLYBRACKET)
                     {
                         return new FixedCardinality(path, min);
                     }
                     else
                     {
                         throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a valid token to continue the Path Cardinality modifier", next);
                     }
                 }
                 else
                 {
                     throw new RdfParseException("The value '" + next.Value + "' is not valid for use as a Path Cardinality modifier", next);
                 }
             }
             else if (next.TokenType == Token.COMMA)
             {
                 next = tokens.Dequeue();
                 if (next.TokenType == Token.PLAINLITERAL)
                 {
                     if (Int32.TryParse(next.Value, out max))
                     {
                         if (max <= 0) throw new RdfParseException("Cannot specify the maximum cardinality for a path as being less than the minimum", next);
                         next = tokens.Dequeue();
                         if (next.TokenType != Token.RIGHTCURLYBRACKET) throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a } to terminate a Path Cardinality modifier", next);
                         if (max == 1)
                         {
                             return new ZeroOrOne(path);
                         }
                         else
                         {
                             return new ZeroToN(path, max);
                         }
                     }
                     else
                     {
                         throw new RdfParseException("The value '" + next.Value + "' is not valid for use as a Path Cardinality modifier", next);
                     }
                 }
                 else
                 {
                     throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an Integer Plain Literal as part of a Path Cardinality modifier", next);
                 }
             }
             else
             {
                 throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an Integer Plain Literal/Comma as part of a Path Cardinality modifier", next);
             }
         default:
             throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a token which is valid as a Path Cardinality modifier", next);
     }
 }
Пример #6
0
 private ISparqlPath TryParsePathElt(SparqlQueryParserContext context, Queue<IToken> tokens)
 {
     return this.TryParsePathPrimary(context, tokens);
 }
Пример #7
0
 private ISparqlPath TryParsePath(SparqlQueryParserContext context, Queue<IToken> tokens)
 {
     return this.TryParsePathAlternative(context, tokens);
 }
Пример #8
0
        private SparqlVariable TryParseAggregate(SparqlQueryParserContext context, IToken agg)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw ParserHelper.Error("Aggregates are not supported in SPARQL 1.0", agg);

            IToken next;
            SparqlVariable var;
            ISparqlAggregate aggregate;

            //Check that the Token is an Aggregate Keyword Token
            switch (agg.TokenType)
            {
                case Token.AVG:
                case Token.COUNT:
                case Token.GROUPCONCAT:
                case Token.MAX:
                case Token.MEDIAN:
                case Token.MIN:
                case Token.MODE:
                case Token.NMAX:
                case Token.NMIN:
                case Token.SAMPLE:
                case Token.SUM:
                    //OK
                    break;

                default:
                    throw ParserHelper.Error("Cannot parse an Aggregate since '" + agg.GetType().ToString() + "' is not an Aggregate Keyword Token", agg);
            }

            //Gather up the Tokens and call into the Expression Parser to get this parsed
            Queue<IToken> tokens = new Queue<IToken>();
            tokens.Enqueue(agg);
            int openBrackets = 0;
            do
            {
                next = context.Tokens.Dequeue();
                if (next.TokenType == Token.LEFTBRACKET)
                {
                    openBrackets++;
                }
                else if (next.TokenType == Token.RIGHTBRACKET)
                {
                    openBrackets--;
                }

                tokens.Enqueue(next);
            } while (openBrackets > 0);

            context.ExpressionParser.AllowAggregates = true;
            ISparqlExpression aggExpr = context.ExpressionParser.Parse(tokens);
            context.ExpressionParser.AllowAggregates = false;

            if (aggExpr is AggregateExpressionTerm)
            {
                aggregate = ((AggregateExpressionTerm)aggExpr).Aggregate;
            }
            else if (aggExpr is NonNumericAggregateExpressionTerm)
            {
                aggregate = ((NonNumericAggregateExpressionTerm)aggExpr).Aggregate;
            }
            else
            {
                throw new RdfParseException("Unexpected expression was parsed when an Aggregate was expected: " + aggExpr.ToString());
            }

            //See if there is an alias
            String alias = "Result";
            next = context.Tokens.Peek();
            if (next.TokenType == Token.AS)
            {
                context.Tokens.Dequeue();
                next = context.Tokens.Dequeue();
                if (next.TokenType != Token.VARIABLE)
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "', expected a Variable Token after an AS Keyword to act as an aliased name for the Aggregate", next);
                }
                alias = next.Value.Substring(1);
            }
            else
            {
                if (context.SyntaxMode != SparqlQuerySyntax.Extended) throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an AS keyword after an Aggregate", next);

                int nextID = context.NextAliasID;
                if (nextID > 0) alias += nextID.ToString();
                while (context.Query.Variables.Any(v => v.Name.Equals(alias)))
                {
                    alias = "Result" + context.NextAliasID;
                }
                this.RaiseWarning("No AS ?variable given for the Aggregate " + aggregate.ToString() + " so assigning alias '" + alias + "'");
            }


            var = new SparqlVariable(alias, aggregate);

            return var;
        }
Пример #9
0
        private void TryParseSubquery(SparqlQueryParserContext context, GraphPattern p)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Sub-queries are not supported in SPARQL 1.0");

            //We're going to make a temporary Token Queue which we will populate and then
            //use to create a new SPARQL Query Parser Context
            NonTokenisedTokenQueue tokens = new NonTokenisedTokenQueue();

            //Assume we've already seen a SELECT
            tokens.Enqueue(new BOFToken());
            tokens.Enqueue(new SelectKeywordToken(1, 1));

            //Now collect Tokens until we hit the closing Right Bracket
            int openBrackets = 1;
            IToken next;
            do
            {
                next = context.Tokens.Peek();

                if (next.TokenType == Token.LEFTCURLYBRACKET)
                {
                    openBrackets++;
                }
                else if (next.TokenType == Token.RIGHTCURLYBRACKET)
                {
                    openBrackets--;
                }
                else if (next.TokenType == Token.EOF)
                {
                    throw ParserHelper.Error("Unexpected End of File encountered while trying to gather Tokens to parse a Sub-Query from", next);
                }

                if (openBrackets > 0)
                {
                    tokens.Enqueue(context.Tokens.Dequeue());
                }
            } while (openBrackets > 0);

            tokens.Enqueue(new EOFToken(0, 0));

            //Create a Sub-query Parser Context
            SparqlQueryParserContext subcontext = new SparqlQueryParserContext(context, tokens);
            subcontext.Query.NamespaceMap.Import(context.Query.NamespaceMap);
            SparqlQuery subquery = this.ParseInternal(subcontext);
            foreach (SparqlVariable var in subquery.Variables)
            {
                if (var.IsResultVariable) context.Query.AddVariable("?" + var.Name, false);
            }
            SubQueryPattern subqueryPattern = new SubQueryPattern(subquery);
            p.AddTriplePattern(subqueryPattern);
        }
Пример #10
0
        private void TryParseBindAssignment(SparqlQueryParserContext context, GraphPattern p)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("BIND assignment is not supported in SPARQL 1.0");

            //First need to discard opening (
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType != Token.LEFTBRACKET) throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a ( to start a BIND assignment after a BIND keyword", next);

            //Expect a bracketted expression terminated by an AS
            ISparqlExpression expr = this.TryParseExpression(context, false, true);
            if (context.Tokens.LastTokenType != Token.AS)
            {
                throw ParserHelper.Error("A BIND assignment did not end with an AS ?var as expected, BIND assignment must be of the general form BIND(expr AS ?var)", next);
            }

            //Ensure there is a Variable after the AS
            next = context.Tokens.Dequeue();
            if (next.TokenType == Token.VARIABLE)
            {
                BindPattern bind = new BindPattern(next.Value.Substring(1), expr);

                //Check that the Variable has not already been used
                if (context.Query.RootGraphPattern != null && context.Query.RootGraphPattern.Variables.Contains(bind.VariableName))
                {
                    throw ParserHelper.Error("A BIND assignment is attempting to bind to the variable ?" + bind.VariableName + " but this variable is already in use in the query", next);
                }
                else if (p.Variables.Contains(bind.VariableName))
                {
                    throw ParserHelper.Error("A BIND assignment is attempting to bind to the variable ?" + bind.VariableName + " but this variable is already in use earlier in the Graph pattern", next);
                }

                if (Options.QueryOptimisation)
                {
                    p.AddAssignment(bind);
                }
                else
                {
                    //When Optimisation is turned off we'll just stick the BIND in the Triples Pattern where it occurs
                    //since we're not going to do any Triple Pattern ordering, Assignment or FILTER placement
                    p.AddTriplePattern(bind);
                    //In this case the BIND must break the BGP since using AddTriplePattern will not do it automatically
                    p.BreakBGP();
                }

                //Ensure the BIND assignment is terminated with a )
                next = context.Tokens.Dequeue();
                if (next.TokenType != Token.RIGHTBRACKET) throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a ) to terminate a BIND assignment", next);
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Variable after the AS in a BIND assignment", next);
            }
        }
Пример #11
0
        private SparqlQuery ParseInternal(TextReader input)
        {
            try
            {
                //Create the Parser Context
                SparqlQueryParserContext context = new SparqlQueryParserContext(new SparqlTokeniser(input, this._syntax), this._queuemode, false, this._tracetokeniser);
                context.SyntaxMode = this._syntax;
                context.ExpressionParser.SyntaxMode = context.SyntaxMode;
                context.ExpressionFactories = this._factories;

                return this.ParseInternal(context);
            }
            catch
            {
                throw;
            }
            finally
            {
                try
                {
                    input.Close();
                }
                catch
                {
                    //No catch actions just trying to clean up the stream
                }
            }
        }
Пример #12
0
        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);
            }
        }
Пример #13
0
        private void TryParseMinusClause(SparqlQueryParserContext context, GraphPattern p)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("MINUS clauses are not supported in SPARQL 1.0");

            //MINUS generates a new child graph pattern
            GraphPattern child = this.TryParseGraphPattern(context);
            child.IsMinus = true;
            p.AddGraphPattern(child);
        }
Пример #14
0
        private void TryParseExistsClause(SparqlQueryParserContext context, GraphPattern p, bool exists)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("EXISTS and NOT EXISTS clauses are not supported in SPARQL 1.0");
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_1) throw new RdfParseException("EXISTS and NOT EXISTS clauses can only be used inside FILTER clauses in SPARQL 1.1");

            //EXISTS and NOT EXISTS generate a new Child Graph Pattern
            GraphPattern child = this.TryParseGraphPattern(context);

            if (exists)
            {
                child.IsExists = true;
            }
            else
            {
                child.IsNotExists = true;
            }

            p.AddGraphPattern(child);
        }
Пример #15
0
        private void TryParseLimitOffsetClause(SparqlQueryParserContext context)
        {
            IToken next = context.Tokens.Dequeue();

            int limit, offset;
            limit = offset = 0;

            if (next.TokenType == Token.LIMIT)
            {
                //Expect a Plain Literal which can be parsed to an Integer
                next = context.Tokens.Dequeue();
                if (next.TokenType == Token.PLAINLITERAL)
                {
                    if (Int32.TryParse(next.Value, out limit))
                    {
                        context.Query.Limit = limit;

                        //Is there a subsequent OFFSET?
                        next = context.Tokens.Peek();
                        if (next.TokenType == Token.OFFSET)
                        {
                            context.Tokens.Dequeue();
                            next = context.Tokens.Dequeue();
                            if (next.TokenType == Token.PLAINLITERAL)
                            {
                                if (Int32.TryParse(next.Value, out offset))
                                {
                                    context.Query.Offset = offset;
                                }
                                else
                                {
                                    throw ParserHelper.Error("Unable to convert string '" + next.Value + "' into an Integer to use as the results offset for a OFFSET Clause", next);
                                }
                            }
                            else
                            {
                                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Plain Literal containing an Integer value as part of the OFFSET Clause", next);
                            }
                        }
                    }
                    else
                    {
                        throw ParserHelper.Error("Unable to convert string '" + next.Value + "' into an Integer to use as the results limit for a LIMIT Clause", next);
                    }
                }
                else
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Plain Literal containing an Integer value as part of the LIMIT Clause", next);
                }
            }
            else if (next.TokenType == Token.OFFSET)
            {
                //Expect a Plain Literal which can be parsed to an Integer
                next = context.Tokens.Dequeue();
                if (next.TokenType == Token.PLAINLITERAL)
                {
                    if (Int32.TryParse(next.Value, out offset))
                    {
                        context.Query.Offset = offset;

                        //Is there a subsequent LIMIT?
                        next = context.Tokens.Peek();
                        if (next.TokenType == Token.LIMIT)
                        {
                            context.Tokens.Dequeue();
                            next = context.Tokens.Dequeue();
                            if (next.TokenType == Token.PLAINLITERAL)
                            {
                                if (Int32.TryParse(next.Value, out limit))
                                {
                                    context.Query.Limit = limit;
                                }
                                else
                                {
                                    throw ParserHelper.Error("Unable to convert string '" + next.Value + "' into an Integer to use as the results limit for a LIMIT Clause", next);
                                }
                            }
                            else
                            {
                                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Plain Literal containing an Integer value as part of the LIMIT Clause", next);
                            }
                        }
                    }
                    else
                    {
                        throw ParserHelper.Error("Unable to convert string '" + next.Value + "' into an Integer to use as the results offset for a OFFSET Clause", next);
                    }
                }
                else
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Plain Literal containing an Integer value as part of the OFFSET Clause", next);
                }
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Limit/Offset Token to start a Limit Offset Clause", next);
            }
        }
Пример #16
0
        private void TryParseSelectVariables(SparqlQueryParserContext context)
        {
            IToken next; 
            bool firstToken = true;
            ISparqlExpression expr;

            //Any Expression we parse from the Select Variables segment may be an aggregate
            context.ExpressionParser.AllowAggregates = true;

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

                switch (next.TokenType)
                {
                    case Token.ALL:
                        if (context.Query.Variables.Count() > 0)
                        {
                            throw ParserHelper.Error("Can't use the * symbol to specify Select All and specify Variables in the SELECT Clause", next);
                        }
                        //Change the Query Type to a Select All
                        switch (context.Query.QueryType)
                        {
                            case SparqlQueryType.Select:
                                context.Query.QueryType = SparqlQueryType.SelectAll;
                                break;
                            case SparqlQueryType.SelectDistinct:
                                context.Query.QueryType = SparqlQueryType.SelectAllDistinct;
                                break;
                            case SparqlQueryType.SelectReduced:
                                context.Query.QueryType = SparqlQueryType.SelectAllReduced;
                                break;
                        }
                        break;

                    case Token.VARIABLE:
                        if ((int)context.Query.QueryType >= (int)SparqlQueryType.SelectAll)
                        {
                            throw ParserHelper.Error("Can't use the * symbol to specify Select All and specify Variables in the SELECT Clause", next);
                        }

                        context.Query.AddVariable(next.Value, true);
                        break;

                    case Token.AVG:
                    case Token.COUNT:
                    case Token.GROUPCONCAT:
                    case Token.MAX:
                    case Token.MEDIAN:
                    case Token.MIN:
                    case Token.MODE:
                    case Token.NMAX:
                    case Token.NMIN:
                    case Token.SAMPLE:
                    case Token.SUM:
                        if ((int)context.Query.QueryType >= (int)SparqlQueryType.SelectAll)
                        {
                            throw ParserHelper.Error("Can't use the * symbol to specify Select All and specify an Aggregate in the SELECT Clause", next);
                        }

                        context.Tokens.Dequeue();
                        SparqlVariable aggVar = this.TryParseAggregate(context, next);
                        context.Query.AddVariable(aggVar);
                        firstToken = false;
                        continue;

                    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:
                        if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Project Expressions are not supported in SPARQL 1.0");

                        expr = this.TryParseFunctionExpression(context);

                        //Need to see the Alias
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.AS)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an AS Keyword after a Projection Expression", next);
                        }
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.VARIABLE)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Variable as an alias after an AS Keyword", next);
                        }

                        context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), expr));
                        firstToken = false;
                        continue;

                    case Token.QNAME:
                    case Token.URI:
                        if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Project Expressions are not supported in SPARQL 1.0");

                        //Try and parse a Project Expression which is a naked function call
                        //Resolve the URI
                        Uri u = new Uri(Tools.ResolveUriOrQName(next, context.Query.NamespaceMap, context.Query.BaseUri));
                        context.Tokens.Dequeue();

                        //Ensure we then see a Open Bracket
                        if (context.Tokens.Peek().TokenType != Token.LEFTBRACKET)
                        {
                            throw ParserHelper.Error("Expected a Left Bracket after a URI/QName in Select Variables for the arguments of a function call", context.Tokens.Peek());
                        }
                        context.Tokens.Dequeue();

                        //Then get the arguments (if any)
                        List<ISparqlExpression> args = new List<ISparqlExpression>();
                        if (context.Tokens.Peek().TokenType == Token.RIGHTBRACKET)
                        {
                            context.Tokens.Dequeue();
                        }
                        else
                        {
                            bool comma = false;
                            do
                            {
                                args.Add(this.TryParseExpression(context, true));
                                comma = (context.Tokens.LastTokenType == Token.COMMA || context.Tokens.LastTokenType == Token.DISTINCT);

                            } while (comma);
                        }

                        //If there are no arguments (one null argument) then discard
                        if (args.Count == 1 && args.First() == null) args.Clear();

                        //Then try and create an Expression
                        expr = SparqlExpressionFactory.CreateExpression(u, args, this._factories);

                        //Need to see the Alias
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.AS)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an AS Keyword after a Projection Expression", next);
                        }
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.VARIABLE)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Variable as an alias after an AS Keyword", next);
                        }

                        //Turn into the appropriate type of Variable
                        if (expr is AggregateExpressionTerm)
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), ((AggregateExpressionTerm)expr).Aggregate));
                        }
                        else if (expr is NonNumericAggregateExpressionTerm)
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), ((NonNumericAggregateExpressionTerm)expr).Aggregate));
                        }
                        else
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), expr));
                        }
                        
                        firstToken = false;
                        continue;

                    case Token.LEFTBRACKET:
                        if ((int)context.Query.QueryType >= (int)SparqlQueryType.SelectAll)
                        {
                            throw ParserHelper.Error("Can't use the * symbol to specify Select All and specify a Projection Expression in the SELECT Clause", next);
                        }

                        if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("Project Expressions are not supported in SPARQL 1.0");

                        //Parse the Expression
                        context.Tokens.Dequeue();
                        expr = this.TryParseExpression(context, false, true);

                        //Require an alias for a Projection Expression
                        bool asTerminated = (context.Tokens.LastTokenType == Token.AS);
                        if (!asTerminated)
                        {
                            //Still need to see an AS
                            next = context.Tokens.Dequeue();
                            if (next.TokenType != Token.AS)
                            {
                                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected an AS Keyword after a Projection Expression", next);
                            }
                        }
                        next = context.Tokens.Dequeue();
                        if (next.TokenType != Token.VARIABLE)
                        {
                            throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Variable as an alias after an AS Keyword", next);
                        }

                        //Turn into the appropriate type of Variable
                        if (expr is AggregateExpressionTerm)
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), ((AggregateExpressionTerm)expr).Aggregate));
                        }
                        else if (expr is NonNumericAggregateExpressionTerm)
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), ((NonNumericAggregateExpressionTerm)expr).Aggregate));
                        }
                        else
                        {
                            context.Query.AddVariable(new SparqlVariable(next.Value.Substring(1), expr));
                        }

                        firstToken = false;
                        if (asTerminated)
                        {
                            //Still need a Right Bracket to terminate the expression since the alias was within the outer brackets
                            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 Projection Expression after the alias", next);
                            }
                        }
                        continue;

                    case Token.DISTINCT:
                        if (firstToken)
                        {
                            context.Query.QueryType = SparqlQueryType.SelectDistinct;
                        }
                        else
                        {
                            throw ParserHelper.Error("The DISTINCT Keyword must occur immediately after the SELECT Verb in a Query", next);
                        }
                        break;

                    case Token.REDUCED:
                        if (firstToken)
                        {
                            context.Query.QueryType = SparqlQueryType.SelectReduced;
                        }
                        else
                        {
                            throw ParserHelper.Error("The REDUCED Keyword must occur immediately after the SELECT Verb in a Query", next);
                        }
                        break;

                    case Token.COMMENT:
                        //Discard Comments
                        context.Tokens.Dequeue();
                        continue;

                    default:
                        if (firstToken)
                        {
                            throw ParserHelper.Error("The SELECT Keyword must be followed by a list of one/more variables or a * to specify all variables", next);
                        }
                        context.ExpressionParser.AllowAggregates = false;
                        return;
                }

                context.Tokens.Dequeue();
                firstToken = false;
            } while (true);
        }
Пример #17
0
        private void TryParseServiceClause(SparqlQueryParserContext context, GraphPattern p)
        {
            if (context.SyntaxMode == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("SERVICE clauses are not supported in SPARQL 1.0");

            //May allow an optional SILENT keyword
            bool silent = false;
            if (context.Tokens.Peek().TokenType == Token.SILENT)
            {
                context.Tokens.Dequeue();
                silent = true;
            }

            //SERVICE first has a URI/Variable service specifier
            IToken specifier = context.Tokens.Dequeue();
            if (specifier.TokenType != Token.URI && specifier.TokenType != Token.VARIABLE)
            {
                throw ParserHelper.Error("Unexpected Token '" + specifier.GetType().ToString() + "' encountered, expected a URI/Variable after a SERVICE keyword", specifier);
            }

            //Then a Graph Pattern
            GraphPattern child = this.TryParseGraphPattern(context);
            child.IsService = true;
            child.GraphSpecifier = specifier;
            child.IsSilent = silent;
            p.AddGraphPattern(child);
        }
Пример #18
0
        private ISparqlPath TryParseNegatedPropertySet(SparqlQueryParserContext context, Queue<IToken> tokens)
        {
            IToken next = tokens.Peek();
            bool inverse;
            Property p;

            switch (next.TokenType)
            {
                case Token.QNAME:
                case Token.URI:
                case Token.KEYWORDA:
                case Token.HAT:
                    p = this.TryParsePathOneInPropertySet(context, tokens, out inverse);
                    if (inverse)
                    {
                        return new NegatedSet(Enumerable.Empty<Property>(), p.AsEnumerable());
                    }
                    else
                    {
                        return new NegatedSet(p.AsEnumerable(), Enumerable.Empty<Property>());
                    }

                case Token.LEFTBRACKET:
                    List<Property> ps = new List<Property>();
                    List<Property> inverses = new List<Property>();

                    tokens.Dequeue();
                    next = tokens.Peek();
                    while (next.TokenType != Token.RIGHTBRACKET)
                    {
                        //Parse the next item in the set
                        p = this.TryParsePathOneInPropertySet(context, tokens, out inverse);
                        if (inverse)
                        {
                            inverses.Add(p);
                        }
                        else
                        {
                            ps.Add(p);
                        }

                        //Then there may be an optional | which we should discard
                        next = tokens.Peek();
                        if (next.TokenType == Token.BITWISEOR)
                        {
                            tokens.Dequeue();
                            next = tokens.Peek();
                            //If we see this we can't then see a ) immediately
                            if (next.TokenType == Token.RIGHTBRACKET) throw new RdfParseException("Unexpected ) to end a negated property set encountered immediately after a | which should indicate that further items are in the set", next);
                        }
                    }
                    tokens.Dequeue();

                    if (ps.Count == 0 && inverses.Count == 0)
                    {
                        throw new RdfParseException("Unexpected empty negated property set encountered", next);
                    }
                    else
                    {
                        return new NegatedSet(ps, inverses);
                    }

                default:
                    throw new RdfParseException("Unexpected Token Type '" + next.GetType().Name + "' encountered, expected the first path in a negated property set", next);

            }
        }
Пример #19
0
        private void TryParseBindingsClause(SparqlQueryParserContext context)
        {
            //First expect one/more variables
            IToken next = context.Tokens.Peek();
            List<String> vars = new List<String>();
            while (next.TokenType == Token.VARIABLE)
            {
                vars.Add(next.Value.Substring(1));
                context.Tokens.Dequeue();
                next = context.Tokens.Peek();
            }
            if (vars.Count == 0)
            {
                //If No Variables then expect an empty BINDINGS { }
                next = context.Tokens.Peek();
                if (next.TokenType != Token.LEFTCURLYBRACKET)
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected either one/more Variable Tokens or the empty set { } after a BINDINGS keyword", next);
                }
            }

            //Then expect a Left Curly Bracket
            if (next.TokenType == Token.LEFTCURLYBRACKET)
            {
                context.Tokens.Dequeue();
                BindingsPattern bindings = new BindingsPattern(vars);

                //Each Binding tuple must start with a (
                next = context.Tokens.Peek();
                while (next.TokenType == Token.LEFTBRACKET)
                {
                    //Discard the ( and peek the next token
                    context.Tokens.Dequeue();
                    next = context.Tokens.Peek();

                    //Expect a sequence of values in the tuple
                    List<PatternItem> values = new List<PatternItem>();
                    while (next.TokenType != Token.RIGHTBRACKET)
                    {
                        next = context.Tokens.Dequeue();

                        //Get the value
                        switch (next.TokenType)
                        {
                            case Token.URI:
                            case Token.QNAME:
                            case Token.LITERALWITHDT:
                            case Token.LITERALWITHLANG:
                            case Token.PLAINLITERAL:
                                values.Add(this.TryCreatePatternItem(context, next));
                                break;

                            case Token.LONGLITERAL:
                            case Token.LITERAL:
                                //Need to check for subsequent datatype or language declaration
                                IToken lit = next;
                                next = context.Tokens.Peek();
                                if (next.TokenType == Token.HATHAT)
                                {
                                    context.Tokens.Dequeue();
                                    next = context.Tokens.Dequeue();
                                    if (next.TokenType == Token.DATATYPE)
                                    {
                                        LiteralWithDataTypeToken dtlit = new LiteralWithDataTypeToken(lit, (DataTypeToken)next);
                                        values.Add(this.TryCreatePatternItem(context, dtlit));
                                    }
                                    else
                                    {
                                        throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Datatype Token to specify the datatype for a Literal", next);
                                    }
                                }
                                else if (next.TokenType == Token.LANGSPEC)
                                {
                                    context.Tokens.Dequeue();
                                    LiteralWithLanguageSpecifierToken langlit = new LiteralWithLanguageSpecifierToken(lit, (LanguageSpecifierToken)next);
                                    values.Add(this.TryCreatePatternItem(context, langlit));
                                }
                                else
                                {
                                    values.Add(this.TryCreatePatternItem(context, lit));
                                }
                                break;

                            case Token.UNDEF:
                                //UNDEF indicates an unbound variable which equates to a null
                                values.Add(null);
                                break;

                            default:
                                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Token for a URI/Literal or an UNDEF keyword as part of a tuple in a BINDINGS clause", next);
                        }

                        next = context.Tokens.Peek();
                    }

                    if (vars.Count != values.Count)
                    {
                        throw new RdfParseException("Invalid tuple in the BINDINGS clause, each Binding should contain " + vars.Count + " values but got a tuple containing " + values.Count + " values");
                    }

                    //Generate a representation of this possible solution and add it to our Bindings object
                    bindings.AddTuple(new BindingTuple(vars, values));

                    //Discard the ) and peek the next token
                    context.Tokens.Dequeue();
                    next = context.Tokens.Peek();
                }

                //Set the Query's BINDINGS clause
                context.Query.Bindings = bindings;

                //Finally we need to see a Right Curly Bracket
                if (next.TokenType != Token.RIGHTCURLYBRACKET)
                {
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Right Curly Bracket to terminate the BINDINGS clause", next);
                }
                context.Tokens.Dequeue();
            }
            else
            {
                throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Left Curly Bracket after the list of variables as part of a BINDINGS clause", next);
            }
        }
Пример #20
0
        private ISparqlPath TryParsePathAlternative(SparqlQueryParserContext context, Queue<IToken> tokens)
        {
            ISparqlPath path = this.TryParsePathSequence(context, tokens);
            IToken next;
            while (tokens.Count > 0)
            {
                next = tokens.Dequeue();
                if (next.TokenType == Token.BITWISEOR)
                {
                    path = new AlternativePath(path, this.TryParsePathSequence(context, tokens));
                }
                else
                {
                    throw new RdfParseException("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a valid path sequence/alternative token", next);
                }
            }

            return path;
        }
Пример #21
0
        private SparqlQuery ParseInternal(SparqlQueryParserContext context)
        {
            IToken temp = null;

            //Initialise Context with relevant data
            context.DefaultBaseUri = this._defaultBaseUri;
            context.ExpressionParser.NamespaceMap = context.Query.NamespaceMap;
            context.ExpressionParser.QueryParser = this;
            context.ExpressionParser.ExpressionFactories = context.ExpressionFactories;
            context.Tokens.InitialiseBuffer();
            context.SyntaxMode = this._syntax;

            do
            {
                temp = context.Tokens.Dequeue();

                switch (temp.TokenType)
                {
                    case Token.BOF:
                    case Token.COMMENT:
                    case Token.EOF:
                        //Discardable Tokens
                        break;

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

                    case Token.ASK:
                    case Token.CONSTRUCT:
                    case Token.DESCRIBE:
                    case Token.SELECT:
                        this.TryParseQueryVerb(context, temp);

                        //Get Variables for a Select or Describe or Construct
                        if (context.Query.QueryType == SparqlQueryType.Select)
                        {
                            this.TryParseSelectVariables(context);
                        }
                        else if (context.Query.QueryType == SparqlQueryType.Describe)
                        {
                            this.TryParseDescribeVariables(context);
                        }
                        else if (context.Query.QueryType == SparqlQueryType.Construct)
                        {
                            this.TryParseConstructTemplate(context);
                        }

                        //Get Datasets (FROM Clauses)
                        temp = context.Tokens.Peek();
                        while (temp.TokenType == Token.FROM)
                        {
                            this.TryParseFrom(context);
                            temp = context.Tokens.Peek();
                        }

                        //Unless a SHORT Form CONSTRUCT then we need to check for a WHERE { } clause
                        //If the Query is a DESCRIBE then if there is no WHERE keyword the WHERE clause is not required
                        if (context.Query.QueryType != SparqlQueryType.Construct || (context.Query.QueryType == SparqlQueryType.Construct && context.Query.RootGraphPattern == null))
                        {
                            //Check for Optional WHERE and Discard
                            temp = context.Tokens.Peek();
                            bool whereSeen = false;
                            if (temp.TokenType == Token.WHERE)
                            {
                                context.Tokens.Dequeue();
                                whereSeen = true;
                            }

                            //Unless it's a DESCRIBE we must now see a Graph Pattern 
                            //OR if the next Token is a { then it must be a Graph Pattern regardless
                            //OR we saw a WHERE in which case we must have a Graph Pattern
                            temp = context.Tokens.Peek();
                            if (whereSeen || context.Query.QueryType != SparqlQueryType.Describe || temp.TokenType == Token.LEFTCURLYBRACKET)
                            {
                                this.TryParseGraphPatterns(context);
                            }
                        }

                        //If we're an ASK then we shouldn't have any Solution Modifier
                        if (context.Query.QueryType == SparqlQueryType.Ask) continue;

                        //Otherwise we can now have a Solution Modifier

                        //Firstly a possible GROUP BY clause
                        temp = context.Tokens.Peek();
                        if (temp.TokenType == Token.GROUPBY)
                        {
                            context.Tokens.Dequeue();
                            this.TryParseGroupByClause(context);

                            //Then a possible HAVING clause
                            temp = context.Tokens.Peek();
                            if (temp.TokenType == Token.HAVING)
                            {
                                context.Tokens.Dequeue();
                                this.TryParseHavingClause(context);
                            }
                        }
                        else if (temp.TokenType == Token.HAVING)
                        {
                            //Can have a HAVING without a GROUP BY
                            context.Tokens.Dequeue();
                            this.TryParseHavingClause(context);
                        }

                        //Check that either there are no Aggregates used or only Aggregates used
                        if (SparqlSpecsHelper.IsSelectQuery(context.Query.QueryType) && (context.Query.IsAggregate && context.Query.GroupBy == null && context.Query.Variables.Any(v => v.IsResultVariable && !v.IsAggregate)))
                        {
                            throw new RdfParseException("The Select Query is invalid since it contains both Aggregates and Variables in the SELECT Clause but it does not contain a GROUP BY clause");
                        }

                        //Then a possible ORDER BY clause
                        temp = context.Tokens.Peek();
                        if (temp.TokenType == Token.ORDERBY)
                        {
                            context.Tokens.Dequeue();
                            this.TryParseOrderByClause(context);
                        }

                        //Then a possible LIMIT/OFFSET clause
                        temp = context.Tokens.Peek();
                        if (temp.TokenType == Token.LIMIT || temp.TokenType == Token.OFFSET)
                        {
                            this.TryParseLimitOffsetClause(context);
                        }

                        //Finally if we're a SELECT then we can have a BINDINGS clause
                        if (SparqlSpecsHelper.IsSelectQuery(context.Query.QueryType))
                        {
                            temp = context.Tokens.Peek();
                            if (temp.TokenType == Token.BINDINGS)
                            {
                                context.Tokens.Dequeue();
                                this.TryParseBindingsClause(context);
                            }
                        }

                        break;

                    default:
                        if (context.Query.QueryType == SparqlQueryType.Ask)
                        {
                            throw ParserHelper.Error("Unexpected Token encountered, a valid ASK query has been parsed but additional invalid tokens are present after the Graph pattern", temp);
                        }
                        else
                        {
                            throw ParserHelper.Error("Unexpected Token encountered - expected a BASE/PREFIX directive or a Query Keyword to start a Query", temp);
                        }
                }
            } while (temp.TokenType != Token.EOF);

            //If not SPARQL 1.0 then do additional post parsing checks
            if (this._syntax != SparqlQuerySyntax.Sparql_1_0)
            {
                switch (context.Query.QueryType)
                {
                    case SparqlQueryType.Select:
                    case SparqlQueryType.SelectDistinct:
                    case SparqlQueryType.SelectReduced:
                    case SparqlQueryType.Describe:
                        //Check Variable Usage
                        List<String> projectedSoFar = new List<string>();
                        foreach (SparqlVariable var in context.Query.Variables)
                        {
                            if (!var.IsResultVariable) continue;

                            if (projectedSoFar.Contains(var.Name) && (var.IsAggregate || var.IsProjection))
                            {
                                throw new RdfParseException("Cannot assign the results of an Aggregate/Project Expression to the variable " + var.ToString() + " as this Variable is already Projected to earlier in the SELECT");
                            }

                            if (var.IsProjection)
                            {
                                if (context.Query.GroupBy != null)
                                {
                                    if (!var.Projection.Variables.All(v => context.Query.GroupBy.ProjectableVariables.Contains(v) || projectedSoFar.Contains(v)))
                                    {
                                        throw new RdfParseException("Your SELECT uses the Project Expression " + var.Projection.ToString() + " which uses one/more Variables which are either not projectable from the GROUP BY or not projected earlier in the SELECT.  All Variables used must be projectable from the GROUP BY or projected earlier in the SELECT");
                                    }
                                }
                            }
                            else if (var.IsAggregate)
                            {
                                if (context.Query.GroupBy != null)
                                {
                                    //Q: Does ISparqlAggregate needs to expose a Variables property?
                                    //if (!var.Aggregate.Var
                                }
                            }
                            else
                            {
                                if (context.Query.GroupBy != null)
                                {
                                    //If there is a GROUP BY then the Variable must either be projectable from there
                                    if (!context.Query.GroupBy.ProjectableVariables.Contains(var.Name))
                                    {
                                        throw new RdfParseException("Your SELECT/DESCRIBE query tries to project the variable " + var.ToString() + " but this Variable is not Grouped By");
                                    }
                                }
                            }

                            projectedSoFar.Add(var.Name);
                        }
                        break;

                    case SparqlQueryType.DescribeAll:
                    case SparqlQueryType.SelectAll:
                    case SparqlQueryType.SelectAllDistinct:
                    case SparqlQueryType.SelectAllReduced:
                        //Check that a GROUP BY has not been used
                        if (context.Query.GroupBy != null)
                        {
                            throw new RdfParseException("SELECT/DESCRIBE * is not permitted when a GROUP BY is used");
                        }
                        break;
                }
            }

            //Optimise the Query if the global option is enabled
            if (Options.QueryOptimisation)
            {
                //If a locally scoped optimiser is available use that
                if (this._optimiser != null)
                {
                    context.Query.Optimise(this._optimiser);
                }
                else
                {
                    context.Query.Optimise();
                }
            }

            return context.Query;
        }
Пример #22
0
 private ISparqlPath TryParsePathEltOrInverse(SparqlQueryParserContext context, Queue<IToken> tokens)
 {
     IToken next = tokens.Peek();
     if (next.TokenType == Token.HAT)
     {
         tokens.Dequeue();
         return new InversePath(this.TryParsePathElt(context, tokens));
     }
     else
     {
         return this.TryParsePathElt(context, tokens);
     }
 }
Пример #23
0
        private PatternItem TryCreatePatternItem(SparqlQueryParserContext context, IToken t)
        {
            String baseUri;
            Uri u;

            switch (t.TokenType)
            {
                case Token.VARIABLE:
                    //Variables accept any Node as a substitution
                    return new VariablePattern(t.Value);

                case Token.URI:
                    //Uri uses a Node Match
                    if (t.Value.StartsWith("_:"))
                    {
                        return new FixedBlankNodePattern(t.Value);
                    }
                    else
                    {
                        String uri = Tools.ResolveUri(t.Value, context.Query.BaseUri.ToSafeString());
                        u = new Uri(uri);
                        //if (Options.UriNormalization)
                        //{
                            return new NodeMatchPattern(new UriNode(null, u));
                        //}
                        //else
                        //{
                        //    return new NodeMatchPattern(new NonNormalizedUriNode(null, uri));
                        //}
                    }

                case Token.QNAME:
                    //QName uses a Node Match
                    //if (Options.UriNormalization)
                    //{
                        return new NodeMatchPattern(new UriNode(null, this.ResolveQName(context, t.Value)));
                    //}
                    //else
                    //{
                    //    return new NodeMatchPattern(new NonNormalizedUriNode(null, Tools.ResolveQName(t.Value, context.Query.NamespaceMap, context.Query.BaseUri)));
                    //}

                case Token.LITERAL:
                case Token.LONGLITERAL:
                    //Literals use Node Matches
                    return new NodeMatchPattern(new NonNormalizedLiteralNode(null, t.Value));

                case Token.PLAINLITERAL:
                    //Plain Literals either use an inferred Literal Node Match
                    //We know it must be one of the inferrable types or the Parser would have failed at the Tokenisation stage for the Literal
                    if (TurtleSpecsHelper.IsValidDouble(t.Value))
                    {
                        //Double - Check first since to be considered a double must contain an exponent so is unique compared to 
                        //the other two numeric types
                        return new NodeMatchPattern(new LiteralNode(null, t.Value, new Uri(XmlSpecsHelper.XmlSchemaDataTypeDouble)));
                    }
                    else if (TurtleSpecsHelper.IsValidInteger(t.Value))
                    {
                        //Integer - Check before decimal as any valid integer is a valid decimal
                        return new NodeMatchPattern(new LiteralNode(null, t.Value, new Uri(XmlSpecsHelper.XmlSchemaDataTypeInteger)));
                    }
                    else if (TurtleSpecsHelper.IsValidDecimal(t.Value))
                    {
                        //Decimal - Check last since any valid integer is also a valid decimal
                        return new NodeMatchPattern(new LiteralNode(null, t.Value, new Uri(XmlSpecsHelper.XmlSchemaDataTypeDecimal)));
                    }
                    else
                    {
                        //Boolean
                        return new NodeMatchPattern(new LiteralNode(null, t.Value, new Uri(XmlSpecsHelper.XmlSchemaDataTypeBoolean)));
                    }


                case Token.LITERALWITHDT:
                    //Literal with Datatype use Node Matches
                    LiteralWithDataTypeToken litdt = (LiteralWithDataTypeToken)t;
                    if (litdt.DataType.StartsWith("<"))
                    {
                        baseUri = (context.Query.BaseUri == null) ? String.Empty : context.Query.BaseUri.ToString();
                        u = new Uri(Tools.ResolveUri(litdt.DataType.Substring(1, litdt.DataType.Length - 2), baseUri));
                        return new NodeMatchPattern(new NonNormalizedLiteralNode(null, litdt.Value, u));
                    }
                    else
                    {
                        //Resolve the QName                       
                        return new NodeMatchPattern(new NonNormalizedLiteralNode(null, litdt.Value, this.ResolveQName(context, litdt.DataType)));
                    }

                case Token.LITERALWITHLANG:
                    //Literal with Lang Spec use Node Matches
                    LiteralWithLanguageSpecifierToken litls = (LiteralWithLanguageSpecifierToken)t;
                    return new NodeMatchPattern(new NonNormalizedLiteralNode(null, litls.Value, litls.Language));

                case Token.BLANKNODEWITHID:
                    //Blanks accept any Blank
                    return new BlankNodePattern(t.Value.Substring(2));

                case Token.KEYWORDA:
                    return new NodeMatchPattern(new UriNode(null, new Uri(NamespaceMapper.RDF + "type")));

                default:
                    throw ParserHelper.Error("Unable to Convert a '" + t.GetType().ToString() + "' to a Pattern Item in a Triple Pattern", t);
            }
        }
Пример #24
0
        private Property TryParsePathOneInPropertySet(SparqlQueryParserContext context, Queue<IToken> tokens, out bool inverse)
        {
            IToken next = tokens.Dequeue();
            inverse = false;
            switch (next.TokenType)
            {
                case Token.URI:
                case Token.QNAME:
                    return new Property(new UriNode(null, UriFactory.Create(Tools.ResolveUriOrQName(next, context.Query.NamespaceMap, context.Query.BaseUri))));

                case Token.KEYWORDA:
                    return new Property(new UriNode(null, UriFactory.Create(RdfSpecsHelper.RdfType)));

                case Token.HAT:
                    next = tokens.Dequeue();
                    inverse = true;
                    switch (next.TokenType)
                    {
                        case Token.URI:
                        case Token.QNAME:
                            return new Property(new UriNode(null, UriFactory.Create(Tools.ResolveUriOrQName(next, context.Query.NamespaceMap, context.Query.BaseUri))));

                        case Token.KEYWORDA:
                            return new Property(new UriNode(null, UriFactory.Create(RdfSpecsHelper.RdfType)));

                        default:
                            throw new RdfParseException("Unexpected Token Type '" + next.GetType().Name + "' encountered, expected a QName/URI or the 'a' Keyword after an inverse operator in a negated property set", next);
                    }

                default:
                    throw new RdfParseException("Unexpected Token Type '" + next.GetType().Name + "' encountered, expected a QName/URI or the 'a' Keyword or the inverse operator '^' to define a path in a negated property set", next);
            }
        }
Пример #25
0
 private Uri ResolveQName(SparqlQueryParserContext context, String qname)
 {
     return new Uri(Tools.ResolveQName(qname, context.Query.NamespaceMap, context.Query.BaseUri));
 }
Пример #26
0
        private ISparqlPath TryParsePathSequence(SparqlQueryParserContext context, Queue<IToken> tokens)
        {
            ISparqlPath path = this.TryParsePathEltOrInverse(context, tokens);
            IToken next;
            while (tokens.Count > 0)
            {
                next = tokens.Peek();
                switch (next.TokenType)
                {
                    case Token.DIVIDE:
                        tokens.Dequeue();
                        path = new SequencePath(path, this.TryParsePathEltOrInverse(context, tokens));
                        break;
                    case Token.HAT:
                        tokens.Dequeue();
                        path = new SequencePath(path, new InversePath(this.TryParsePathElt(context, tokens)));
                        break;
                    default:
                        return path;
                }
            }

            return path;
        }
Пример #27
0
        private void TryParseBaseDeclaration(SparqlQueryParserContext context)
        {
            if (context.SubQueryMode) throw new RdfQueryException("BASE Directives are not supported in Sub-queries");

            //Get the next Token which should be a Uri Token
            IToken next = context.Tokens.Dequeue();
            if (next.TokenType == Token.URI)
            {
                context.Query.BaseUri = new Uri(next.Value);
                context.ExpressionParser.BaseUri = context.Query.BaseUri;
            }
            else
            {
                throw ParserHelper.Error("Expected a URI Token to follow the BASE Verb in a Query", next);
            }
        }
Пример #28
0
        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);
            }
        }
Пример #29
0
        private void TryParsePrefixDeclaration(SparqlQueryParserContext context)
        {
            if (context.SubQueryMode) throw new RdfQueryException("PREFIX Directives are not supported in Sub-queries");

            //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.Query.BaseUri != null) ? context.Query.BaseUri.ToString() : String.Empty;
                    Uri u = new Uri(Tools.ResolveUri(uri.Value, baseUri));
                    if (prefix.Value.Length == 1)
                    {
                        //Defining prefix for Default Namespace
                        context.Query.NamespaceMap.AddNamespace("", u);
                    }
                    else
                    {
                        //Defining prefix for some other Namespace
                        context.Query.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 a Query", uri);
                }
            }
            else
            {
                throw ParserHelper.Error("Expected a Prefix Token to follow the PREFIX Verb in a Query", prefix);
            }
        }
Пример #30
0
        private void TryParseQueryVerb(SparqlQueryParserContext context, IToken t)
        {
            if (context.VerbSeen)
            {
                throw ParserHelper.Error("Only 1 Query Verb can occur in a Query", t);
            }
            else
            {
                context.VerbSeen = true;

                switch (t.TokenType) {
                    case Token.ASK:
                        if (context.SubQueryMode) throw ParserHelper.Error("ASK is not supported in Sub-queries",t);
                        context.Query.QueryType = SparqlQueryType.Ask;
                        break;
                    case Token.CONSTRUCT:
                        if (context.SubQueryMode) throw ParserHelper.Error("CONSTRUCT is not supported in Sub-queries",t);
                        context.Query.QueryType = SparqlQueryType.Construct;
                        break;
                    case Token.DESCRIBE:
                        if (context.SubQueryMode) throw ParserHelper.Error("DESCRIBE is not supported in Sub-queries", t);
                        context.Query.QueryType = SparqlQueryType.Describe;
                        break;
                    case Token.SELECT:
                        context.Query.QueryType = SparqlQueryType.Select;
                        break;
                }
            }
        }
Пример #31
0
        private void TryParseHavingClause(SparqlQueryParserContext context)
        {
            if (this._syntax == SparqlQuerySyntax.Sparql_1_0) throw new RdfParseException("HAVING clauses are not supported in SPARQL 1.0");
            //HAVING Keyword has already been discarded
            IToken next = context.Tokens.Peek();
            ISparqlExpression havingExpr;

            switch (next.TokenType)
            {
                case Token.LEFTBRACKET:
                    //Find and parse the Expression
                    context.Tokens.Dequeue();
                    int openBrackets = 1;
                    Queue<IToken> exprTerms = new Queue<IToken>();
                    while (openBrackets > 0)
                    {
                        //Get next Token
                        next = context.Tokens.Peek();

                        //Take account of nesting
                        if (next.TokenType == Token.LEFTBRACKET)
                        {
                            openBrackets++;
                        }
                        else if (next.TokenType == Token.RIGHTBRACKET)
                        {
                            openBrackets--;
                        }

                        if (openBrackets > 0)
                        {
                            exprTerms.Enqueue(next);
                        }
                        context.Tokens.Dequeue();
                    }

                    //Permit aggregates in the Expression
                    context.ExpressionParser.AllowAggregates = true;
                    havingExpr = context.ExpressionParser.Parse(exprTerms);
                    context.ExpressionParser.AllowAggregates = false;
                    break;

                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:
                    //Built-in function/expression
                    context.ExpressionParser.AllowAggregates = true;
                    havingExpr = this.TryParseFunctionExpression(context);
                    context.ExpressionParser.AllowAggregates = false;
                    break;

                default:
                    throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Left Bracket to start a bracketted expression in a HAVING Clause", next);
            }

            //Set the Having Clause of the Group By
            //For Leviathan we can just wrap in a standard Unary Expression Filter
            context.Query.Having = new UnaryExpressionFilter(havingExpr);
       }