comparison env/lib/python3.7/site-packages/rdflib/plugins/sparql/parser.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 """
2 SPARQL 1.1 Parser
3
4 based on pyparsing
5 """
6
7 import sys
8 import re
9
10 from pyparsing import (
11 Literal, Regex, Optional, OneOrMore, ZeroOrMore, Forward,
12 ParseException, Suppress, Combine, restOfLine, Group,
13 ParseResults, delimitedList)
14 from pyparsing import CaselessKeyword as Keyword # watch out :)
15 # from pyparsing import Keyword as CaseSensitiveKeyword
16
17 from .parserutils import Comp, Param, ParamList
18
19 from . import operators as op
20 from rdflib.py3compat import decodeUnicodeEscape, bytestype
21
22 import rdflib
23
24 DEBUG = False
25
26 # ---------------- ACTIONS
27
28
29 def neg(literal):
30 return rdflib.Literal(-literal, datatype=literal.datatype)
31
32
33 def setLanguage(terms):
34 return rdflib.Literal(terms[0], lang=terms[1])
35
36
37 def setDataType(terms):
38 return rdflib.Literal(terms[0], datatype=terms[1])
39
40
41 def expandTriples(terms):
42
43 """
44 Expand ; and , syntax for repeat predicates, subjects
45 """
46 # import pdb; pdb.set_trace()
47 try:
48 res = []
49 if DEBUG:
50 print("Terms", terms)
51 l = len(terms)
52 for i, t in enumerate(terms):
53 if t == ',':
54 res.extend([res[-3], res[-2]])
55 elif t == ';':
56 if i+1 == len(terms) or terms[i+1] == ";" or terms[i+1] == ".":
57 continue # this semicolon is spurious
58 res.append(res[-3])
59 elif isinstance(t, list):
60 # BlankNodePropertyList
61 # is this bnode the object of previous triples?
62 if (len(res) % 3) == 2:
63 res.append(t[0])
64 # is this a single [] ?
65 if len(t) > 1:
66 res += t
67 # is this bnode the subject of more triples?
68 if i + 1 < l and terms[i + 1] not in ".,;" :
69 res.append(t[0])
70 elif isinstance(t, ParseResults):
71 res += t.asList()
72 elif t != '.':
73 res.append(t)
74 if DEBUG:
75 print(len(res), t)
76 if DEBUG:
77 import json
78 print(json.dumps(res, indent=2))
79
80 return res
81 # print res
82 # assert len(res)%3 == 0, \
83 # "Length of triple-list is not divisible by 3: %d!"%len(res)
84
85 # return [tuple(res[i:i+3]) for i in range(len(res)/3)]
86 except:
87 if DEBUG:
88 import traceback
89 traceback.print_exc()
90 raise
91
92
93 def expandBNodeTriples(terms):
94 """
95 expand [ ?p ?o ] syntax for implicit bnodes
96 """
97 # import pdb; pdb.set_trace()
98 try:
99 if DEBUG:
100 print("Bnode terms", terms)
101 print("1", terms[0])
102 print("2", [rdflib.BNode()] + terms.asList()[0])
103 return [expandTriples([rdflib.BNode()] + terms.asList()[0])]
104 except Exception as e:
105 if DEBUG:
106 print(">>>>>>>>", e)
107 raise
108
109
110 def expandCollection(terms):
111 """
112 expand ( 1 2 3 ) notation for collections
113 """
114 if DEBUG:
115 print("Collection: ", terms)
116
117 res = []
118 other = []
119 for x in terms:
120 if isinstance(x, list): # is this a [ .. ] ?
121 other += x
122 x = x[0]
123
124 b = rdflib.BNode()
125 if res:
126 res += [res[-3], rdflib.RDF.rest, b, b, rdflib.RDF.first, x]
127 else:
128 res += [b, rdflib.RDF.first, x]
129 res += [b, rdflib.RDF.rest, rdflib.RDF.nil]
130
131 res += other
132
133 if DEBUG:
134 print("CollectionOut", res)
135 return [res]
136
137
138 # SPARQL Grammar from http://www.w3.org/TR/sparql11-query/#grammar
139 # ------ TERMINALS --------------
140 # [139] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20])* '>'
141 IRIREF = Combine(Suppress('<') + Regex(r'[^<>"{}|^`\\%s]*' % ''.join(
142 '\\x%02X' % i for i in range(33))) + Suppress('>'))
143 IRIREF.setParseAction(lambda x: rdflib.URIRef(x[0]))
144
145 # [164] P_CHARS_BASE ::= [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
146
147 if sys.maxunicode == 0xffff:
148 # this is narrow python build (default on windows/osx)
149 # this means that unicode code points over 0xffff are stored
150 # as several characters, which in turn means that regex character
151 # ranges with these characters do not work.
152 # See
153 # * http://bugs.python.org/issue12729
154 # * http://bugs.python.org/issue12749
155 # * http://bugs.python.org/issue3665
156 #
157 # Here we simple skip the [#x10000-#xEFFFF] part
158 # this means that some SPARQL queries will not parse :(
159 # We *could* generate a new regex with \U00010000|\U00010001 ...
160 # but it would be quite long :)
161 #
162 # in py3.3 this is fixed
163
164 PN_CHARS_BASE_re = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD'
165 else:
166 # wide python build
167 PN_CHARS_BASE_re = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\U00010000-\U000EFFFF'
168
169 # [165] PN_CHARS_U ::= PN_CHARS_BASE | '_'
170 PN_CHARS_U_re = '_' + PN_CHARS_BASE_re
171
172 # [167] PN_CHARS ::= PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
173 PN_CHARS_re = '\\-0-9\u00B7\u0300-\u036F\u203F-\u2040' + PN_CHARS_U_re
174 # PN_CHARS = Regex(u'[%s]'%PN_CHARS_re, flags=re.U)
175
176 # [168] PN_PREFIX ::= PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
177 PN_PREFIX = Regex(r'[%s](?:[%s\.]*[%s])?' % (PN_CHARS_BASE_re,
178 PN_CHARS_re, PN_CHARS_re), flags=re.U)
179
180 # [140] PNAME_NS ::= PN_PREFIX? ':'
181 PNAME_NS = Optional(
182 Param('prefix', PN_PREFIX)) + Suppress(':').leaveWhitespace()
183
184 # [173] PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )
185
186 PN_LOCAL_ESC_re = '\\\\[_~\\.\\-!$&"\'()*+,;=/?#@%]'
187 #PN_LOCAL_ESC = Regex(PN_LOCAL_ESC_re) # regex'd
188 #PN_LOCAL_ESC.setParseAction(lambda x: x[0][1:])
189
190 # [172] HEX ::= [0-9] | [A-F] | [a-f]
191 # HEX = Regex('[0-9A-Fa-f]') # not needed
192
193 # [171] PERCENT ::= '%' HEX HEX
194 PERCENT_re = '%[0-9a-fA-F]{2}'
195 #PERCENT = Regex(PERCENT_re) # regex'd
196 #PERCENT.setParseAction(lambda x: unichr(int(x[0][1:], 16)))
197
198 # [170] PLX ::= PERCENT | PN_LOCAL_ESC
199 PLX_re = '(%s|%s)'%(PN_LOCAL_ESC_re,PERCENT_re)
200 #PLX = PERCENT | PN_LOCAL_ESC # regex'd
201
202
203 # [169] PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
204
205 PN_LOCAL = Regex(r"""([%(PN_CHARS_U)s:0-9]|%(PLX)s)
206 (([%(PN_CHARS)s\.:]|%(PLX)s)*
207 ([%(PN_CHARS)s:]|%(PLX)s) )?"""%dict(PN_CHARS_U=PN_CHARS_U_re,
208 PN_CHARS=PN_CHARS_re,
209 PLX=PLX_re), flags=re.X|re.UNICODE)
210
211 def _hexExpand(match):
212 return chr(int(match.group(0)[1:], 16))
213
214 PN_LOCAL.setParseAction(lambda x: re.sub("(%s)"%PERCENT_re, _hexExpand, x[0]))
215
216
217
218
219 # [141] PNAME_LN ::= PNAME_NS PN_LOCAL
220 PNAME_LN = PNAME_NS + Param('localname', PN_LOCAL.leaveWhitespace())
221
222 # [142] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
223 BLANK_NODE_LABEL = Regex(r'_:[0-9%s](?:[\.%s]*[%s])?' % (
224 PN_CHARS_U_re, PN_CHARS_re, PN_CHARS_re), flags=re.U)
225 BLANK_NODE_LABEL.setParseAction(lambda x: rdflib.BNode(x[0]))
226
227
228 # [166] VARNAME ::= ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
229 VARNAME = Regex('[%s0-9][%s0-9\u00B7\u0300-\u036F\u203F-\u2040]*' % (
230 PN_CHARS_U_re, PN_CHARS_U_re), flags=re.U)
231
232 # [143] VAR1 ::= '?' VARNAME
233 VAR1 = Combine(Suppress('?') + VARNAME)
234
235 # [144] VAR2 ::= '$' VARNAME
236 VAR2 = Combine(Suppress('$') + VARNAME)
237
238 # [145] LANGTAG ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)*
239 LANGTAG = Combine(Suppress('@') + Regex('[a-zA-Z]+(?:-[a-zA-Z0-9]+)*'))
240
241 # [146] INTEGER ::= [0-9]+
242 INTEGER = Regex(r"[0-9]+")
243 # INTEGER.setResultsName('integer')
244 INTEGER.setParseAction(
245 lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.integer))
246
247 # [155] EXPONENT ::= [eE] [+-]? [0-9]+
248 EXPONENT_re = '[eE][+-]?[0-9]+'
249
250 # [147] DECIMAL ::= [0-9]* '.' [0-9]+
251 DECIMAL = Regex(r'[0-9]*\.[0-9]+') # (?![eE])
252 # DECIMAL.setResultsName('decimal')
253 DECIMAL.setParseAction(
254 lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.decimal))
255
256 # [148] DOUBLE ::= [0-9]+ '.' [0-9]* EXPONENT | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT
257 DOUBLE = Regex(
258 r'[0-9]+\.[0-9]*%(e)s|\.([0-9])+%(e)s|[0-9]+%(e)s' % {'e': EXPONENT_re})
259 # DOUBLE.setResultsName('double')
260 DOUBLE.setParseAction(
261 lambda x: rdflib.Literal(x[0], datatype=rdflib.XSD.double))
262
263
264 # [149] INTEGER_POSITIVE ::= '+' INTEGER
265 INTEGER_POSITIVE = Suppress('+') + INTEGER.copy().leaveWhitespace()
266 INTEGER_POSITIVE.setParseAction(lambda x: rdflib.Literal(
267 "+"+x[0], datatype=rdflib.XSD.integer))
268
269 # [150] DECIMAL_POSITIVE ::= '+' DECIMAL
270 DECIMAL_POSITIVE = Suppress('+') + DECIMAL.copy().leaveWhitespace()
271
272 # [151] DOUBLE_POSITIVE ::= '+' DOUBLE
273 DOUBLE_POSITIVE = Suppress('+') + DOUBLE.copy().leaveWhitespace()
274
275 # [152] INTEGER_NEGATIVE ::= '-' INTEGER
276 INTEGER_NEGATIVE = Suppress('-') + INTEGER.copy().leaveWhitespace()
277 INTEGER_NEGATIVE.setParseAction(lambda x: neg(x[0]))
278
279 # [153] DECIMAL_NEGATIVE ::= '-' DECIMAL
280 DECIMAL_NEGATIVE = Suppress('-') + DECIMAL.copy().leaveWhitespace()
281 DECIMAL_NEGATIVE.setParseAction(lambda x: neg(x[0]))
282
283 # [154] DOUBLE_NEGATIVE ::= '-' DOUBLE
284 DOUBLE_NEGATIVE = Suppress('-') + DOUBLE.copy().leaveWhitespace()
285 DOUBLE_NEGATIVE.setParseAction(lambda x: neg(x[0]))
286
287 # [160] ECHAR ::= '\' [tbnrf\"']
288 # ECHAR = Regex('\\\\[tbnrf"\']')
289
290
291 # [158] STRING_LITERAL_LONG1 ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR ) )* "'''"
292 # STRING_LITERAL_LONG1 = Literal("'''") + ( Optional( Literal("'") | "''"
293 # ) + ZeroOrMore( ~ Literal("'\\") | ECHAR ) ) + "'''"
294 STRING_LITERAL_LONG1 = Regex(r"'''((?:'|'')?(?:[^'\\]|\\['ntbrf\\]))*'''")
295 STRING_LITERAL_LONG1.setParseAction(
296 lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][3:-3])))
297
298 # [159] STRING_LITERAL_LONG2 ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR ) )* '"""'
299 # STRING_LITERAL_LONG2 = Literal('"""') + ( Optional( Literal('"') | '""'
300 # ) + ZeroOrMore( ~ Literal('"\\') | ECHAR ) ) + '"""'
301 STRING_LITERAL_LONG2 = Regex(r'"""(?:(?:"|"")?(?:[^"\\]|\\["ntbrf\\]))*"""')
302 STRING_LITERAL_LONG2.setParseAction(
303 lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][3:-3])))
304
305 # [156] STRING_LITERAL1 ::= "'" ( ([^#x27#x5C#xA#xD]) | ECHAR )* "'"
306 # STRING_LITERAL1 = Literal("'") + ZeroOrMore(
307 # Regex(u'[^\u0027\u005C\u000A\u000D]',flags=re.U) | ECHAR ) + "'"
308
309 STRING_LITERAL1 = Regex(
310 r"'(?:[^'\n\r\\]|\\['ntbrf\\])*'(?!')", flags=re.U)
311 STRING_LITERAL1.setParseAction(
312 lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][1:-1])))
313
314 # [157] STRING_LITERAL2 ::= '"' ( ([^#x22#x5C#xA#xD]) | ECHAR )* '"'
315 # STRING_LITERAL2 = Literal('"') + ZeroOrMore (
316 # Regex(u'[^\u0022\u005C\u000A\u000D]',flags=re.U) | ECHAR ) + '"'
317
318 STRING_LITERAL2 = Regex(
319 r'"(?:[^"\n\r\\]|\\["ntbrf\\])*"(?!")', flags=re.U)
320 STRING_LITERAL2.setParseAction(
321 lambda x: rdflib.Literal(decodeUnicodeEscape(x[0][1:-1])))
322
323 # [161] NIL ::= '(' WS* ')'
324 NIL = Literal('(') + ')'
325 NIL.setParseAction(lambda x: rdflib.RDF.nil)
326
327 # [162] WS ::= #x20 | #x9 | #xD | #xA
328 # Not needed?
329 # WS = #x20 | #x9 | #xD | #xA
330 # [163] ANON ::= '[' WS* ']'
331 ANON = Literal('[') + ']'
332 ANON.setParseAction(lambda x: rdflib.BNode())
333
334 # A = CaseSensitiveKeyword('a')
335 A = Literal('a')
336 A.setParseAction(lambda x: rdflib.RDF.type)
337
338
339 # ------ NON-TERMINALS --------------
340
341 # [5] BaseDecl ::= 'BASE' IRIREF
342 BaseDecl = Comp('Base', Keyword('BASE') + Param('iri', IRIREF))
343
344 # [6] PrefixDecl ::= 'PREFIX' PNAME_NS IRIREF
345 PrefixDecl = Comp(
346 'PrefixDecl', Keyword('PREFIX') + PNAME_NS + Param('iri', IRIREF))
347
348 # [4] Prologue ::= ( BaseDecl | PrefixDecl )*
349 Prologue = Group(ZeroOrMore(BaseDecl | PrefixDecl))
350
351 # [108] Var ::= VAR1 | VAR2
352 Var = VAR1 | VAR2
353 Var.setParseAction(lambda x: rdflib.term.Variable(x[0]))
354
355 # [137] PrefixedName ::= PNAME_LN | PNAME_NS
356 PrefixedName = Comp('pname', PNAME_LN | PNAME_NS)
357
358 # [136] iri ::= IRIREF | PrefixedName
359 iri = IRIREF | PrefixedName
360
361 # [135] String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
362 String = STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2 | STRING_LITERAL1 | STRING_LITERAL2
363
364 # [129] RDFLiteral ::= String ( LANGTAG | ( '^^' iri ) )?
365
366 RDFLiteral = Comp('literal', Param('string', String) + Optional(Param(
367 'lang', LANGTAG.leaveWhitespace()) | Literal('^^').leaveWhitespace() + Param('datatype', iri).leaveWhitespace()))
368
369 # [132] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
370 NumericLiteralPositive = DOUBLE_POSITIVE | DECIMAL_POSITIVE | INTEGER_POSITIVE
371
372 # [133] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
373 NumericLiteralNegative = DOUBLE_NEGATIVE | DECIMAL_NEGATIVE | INTEGER_NEGATIVE
374
375 # [131] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE
376 NumericLiteralUnsigned = DOUBLE | DECIMAL | INTEGER
377
378 # [130] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
379 NumericLiteral = NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
380
381 # [134] BooleanLiteral ::= 'true' | 'false'
382 BooleanLiteral = Keyword('true').setParseAction(lambda: rdflib.Literal(True)) |\
383 Keyword('false').setParseAction(lambda: rdflib.Literal(False))
384
385 # [138] BlankNode ::= BLANK_NODE_LABEL | ANON
386 BlankNode = BLANK_NODE_LABEL | ANON
387
388 # [109] GraphTerm ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL
389 GraphTerm = iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL
390
391 # [106] VarOrTerm ::= Var | GraphTerm
392 VarOrTerm = Var | GraphTerm
393
394 # [107] VarOrIri ::= Var | iri
395 VarOrIri = Var | iri
396
397 # [46] GraphRef ::= 'GRAPH' iri
398 GraphRef = Keyword('GRAPH') + Param('graphiri', iri)
399
400 # [47] GraphRefAll ::= GraphRef | 'DEFAULT' | 'NAMED' | 'ALL'
401 GraphRefAll = GraphRef | Param('graphiri', Keyword('DEFAULT')) | Param(
402 'graphiri', Keyword('NAMED')) | Param('graphiri', Keyword('ALL'))
403
404 # [45] GraphOrDefault ::= 'DEFAULT' | 'GRAPH'? iri
405 GraphOrDefault = ParamList('graph', Keyword(
406 'DEFAULT')) | Optional(Keyword('GRAPH')) + ParamList('graph', iri)
407
408 # [65] DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF'
409 DataBlockValue = iri | RDFLiteral | NumericLiteral | BooleanLiteral | Keyword(
410 'UNDEF')
411
412 # [78] Verb ::= VarOrIri | A
413 Verb = VarOrIri | A
414
415
416 # [85] VerbSimple ::= Var
417 VerbSimple = Var
418
419 # [97] Integer ::= INTEGER
420 Integer = INTEGER
421
422
423 TriplesNode = Forward()
424 TriplesNodePath = Forward()
425
426 # [104] GraphNode ::= VarOrTerm | TriplesNode
427 GraphNode = VarOrTerm | TriplesNode
428
429 # [105] GraphNodePath ::= VarOrTerm | TriplesNodePath
430 GraphNodePath = VarOrTerm | TriplesNodePath
431
432
433 # [93] PathMod ::= '?' | '*' | '+'
434 PathMod = Literal('?') | '*' | '+'
435
436 # [96] PathOneInPropertySet ::= iri | A | '^' ( iri | A )
437 PathOneInPropertySet = iri | A | Comp('InversePath', '^' + (iri | A))
438
439 Path = Forward()
440
441 # [95] PathNegatedPropertySet ::= PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')'
442 PathNegatedPropertySet = Comp('PathNegatedPropertySet', ParamList('part', PathOneInPropertySet) | '(' + Optional(
443 ParamList('part', PathOneInPropertySet) + ZeroOrMore('|' + ParamList('part', PathOneInPropertySet))) + ')')
444
445 # [94] PathPrimary ::= iri | A | '!' PathNegatedPropertySet | '(' Path ')' | 'DISTINCT' '(' Path ')'
446 PathPrimary = iri | A | Suppress('!') + PathNegatedPropertySet | Suppress('(') + Path + Suppress(
447 ')') | Comp('DistinctPath', Keyword('DISTINCT') + '(' + Param('part', Path) + ')')
448
449 # [91] PathElt ::= PathPrimary Optional(PathMod)
450 PathElt = Comp('PathElt', Param(
451 'part', PathPrimary) + Optional(Param('mod', PathMod.leaveWhitespace())))
452
453 # [92] PathEltOrInverse ::= PathElt | '^' PathElt
454 PathEltOrInverse = PathElt | Suppress(
455 '^') + Comp('PathEltOrInverse', Param('part', PathElt))
456
457 # [90] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
458 PathSequence = Comp('PathSequence', ParamList('part', PathEltOrInverse) +
459 ZeroOrMore('/' + ParamList('part', PathEltOrInverse)))
460
461
462 # [89] PathAlternative ::= PathSequence ( '|' PathSequence )*
463 PathAlternative = Comp('PathAlternative', ParamList('part', PathSequence) +
464 ZeroOrMore('|' + ParamList('part', PathSequence)))
465
466 # [88] Path ::= PathAlternative
467 Path << PathAlternative
468
469 # [84] VerbPath ::= Path
470 VerbPath = Path
471
472 # [87] ObjectPath ::= GraphNodePath
473 ObjectPath = GraphNodePath
474
475 # [86] ObjectListPath ::= ObjectPath ( ',' ObjectPath )*
476 ObjectListPath = ObjectPath + ZeroOrMore(',' + ObjectPath)
477
478
479 GroupGraphPattern = Forward()
480
481
482 # [102] Collection ::= '(' OneOrMore(GraphNode) ')'
483 Collection = Suppress('(') + OneOrMore(GraphNode) + Suppress(')')
484 Collection.setParseAction(expandCollection)
485
486 # [103] CollectionPath ::= '(' OneOrMore(GraphNodePath) ')'
487 CollectionPath = Suppress('(') + OneOrMore(GraphNodePath) + Suppress(')')
488 CollectionPath.setParseAction(expandCollection)
489
490 # [80] Object ::= GraphNode
491 Object = GraphNode
492
493 # [79] ObjectList ::= Object ( ',' Object )*
494 ObjectList = Object + ZeroOrMore(',' + Object)
495
496 # [83] PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )*
497 PropertyListPathNotEmpty = (VerbPath | VerbSimple) + ObjectListPath + ZeroOrMore(
498 ';' + Optional((VerbPath | VerbSimple) + ObjectList))
499
500 # [82] PropertyListPath ::= Optional(PropertyListPathNotEmpty)
501 PropertyListPath = Optional(PropertyListPathNotEmpty)
502
503 # [77] PropertyListNotEmpty ::= Verb ObjectList ( ';' ( Verb ObjectList )? )*
504 PropertyListNotEmpty = Verb + ObjectList + ZeroOrMore(';' + Optional(Verb +
505 ObjectList))
506
507
508 # [76] PropertyList ::= Optional(PropertyListNotEmpty)
509 PropertyList = Optional(PropertyListNotEmpty)
510
511 # [99] BlankNodePropertyList ::= '[' PropertyListNotEmpty ']'
512 BlankNodePropertyList = Group(
513 Suppress('[') + PropertyListNotEmpty + Suppress(']'))
514 BlankNodePropertyList.setParseAction(expandBNodeTriples)
515
516 # [101] BlankNodePropertyListPath ::= '[' PropertyListPathNotEmpty ']'
517 BlankNodePropertyListPath = Group(
518 Suppress('[') + PropertyListPathNotEmpty + Suppress(']'))
519 BlankNodePropertyListPath.setParseAction(expandBNodeTriples)
520
521 # [98] TriplesNode ::= Collection | BlankNodePropertyList
522 TriplesNode << (Collection | BlankNodePropertyList)
523
524 # [100] TriplesNodePath ::= CollectionPath | BlankNodePropertyListPath
525 TriplesNodePath << (CollectionPath | BlankNodePropertyListPath)
526
527 # [75] TriplesSameSubject ::= VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList
528 TriplesSameSubject = VarOrTerm + PropertyListNotEmpty | TriplesNode + \
529 PropertyList
530 TriplesSameSubject.setParseAction(expandTriples)
531
532 # [52] TriplesTemplate ::= TriplesSameSubject ( '.' Optional(TriplesTemplate) )?
533 TriplesTemplate = Forward()
534 TriplesTemplate << (ParamList('triples', TriplesSameSubject) + Optional(
535 Suppress('.') + Optional(TriplesTemplate)))
536
537 # [51] QuadsNotTriples ::= 'GRAPH' VarOrIri '{' Optional(TriplesTemplate) '}'
538 QuadsNotTriples = Comp('QuadsNotTriples', Keyword('GRAPH') + Param(
539 'term', VarOrIri) + '{' + Optional(TriplesTemplate) + '}')
540
541 # [50] Quads ::= Optional(TriplesTemplate) ( QuadsNotTriples '.'? Optional(TriplesTemplate) )*
542 Quads = Comp('Quads', Optional(TriplesTemplate) + ZeroOrMore(ParamList(
543 'quadsNotTriples', QuadsNotTriples) + Optional(Suppress('.')) + Optional(TriplesTemplate)))
544
545 # [48] QuadPattern ::= '{' Quads '}'
546 QuadPattern = '{' + Param('quads', Quads) + '}'
547
548 # [49] QuadData ::= '{' Quads '}'
549 QuadData = '{' + Param('quads', Quads) + '}'
550
551 # [81] TriplesSameSubjectPath ::= VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath
552 TriplesSameSubjectPath = VarOrTerm + \
553 PropertyListPathNotEmpty | TriplesNodePath + PropertyListPath
554 TriplesSameSubjectPath.setParseAction(expandTriples)
555
556 # [55] TriplesBlock ::= TriplesSameSubjectPath ( '.' Optional(TriplesBlock) )?
557 TriplesBlock = Forward()
558 TriplesBlock << (ParamList('triples', TriplesSameSubjectPath) + Optional(
559 Suppress('.') + Optional(TriplesBlock)))
560
561
562 # [66] MinusGraphPattern ::= 'MINUS' GroupGraphPattern
563 MinusGraphPattern = Comp(
564 'MinusGraphPattern', Keyword('MINUS') + Param('graph', GroupGraphPattern))
565
566 # [67] GroupOrUnionGraphPattern ::= GroupGraphPattern ( 'UNION' GroupGraphPattern )*
567 GroupOrUnionGraphPattern = Comp('GroupOrUnionGraphPattern', ParamList(
568 'graph', GroupGraphPattern) + ZeroOrMore(Keyword('UNION') + ParamList('graph', GroupGraphPattern)))
569
570
571 Expression = Forward()
572
573 # [72] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')'
574 ExpressionList = NIL | Group(
575 Suppress('(') + delimitedList(Expression) + Suppress(')'))
576
577 # [122] RegexExpression ::= 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')'
578 RegexExpression = Comp('Builtin_REGEX', Keyword('REGEX') + '(' + Param('text', Expression) + ',' + Param(
579 'pattern', Expression) + Optional(',' + Param('flags', Expression)) + ')')
580 RegexExpression.setEvalFn(op.Builtin_REGEX)
581
582 # [123] SubstringExpression ::= 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')'
583 SubstringExpression = Comp('Builtin_SUBSTR', Keyword('SUBSTR') + '(' + Param('arg', Expression) + ',' + Param(
584 'start', Expression) + Optional(',' + Param('length', Expression)) + ')').setEvalFn(op.Builtin_SUBSTR)
585
586 # [124] StrReplaceExpression ::= 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')'
587 StrReplaceExpression = Comp('Builtin_REPLACE', Keyword('REPLACE') + '(' + Param('arg', Expression) + ',' + Param(
588 'pattern', Expression) + ',' + Param('replacement', Expression) + Optional(',' + Param('flags', Expression)) + ')').setEvalFn(op.Builtin_REPLACE)
589
590 # [125] ExistsFunc ::= 'EXISTS' GroupGraphPattern
591 ExistsFunc = Comp('Builtin_EXISTS', Keyword('EXISTS') + Param(
592 'graph', GroupGraphPattern)).setEvalFn(op.Builtin_EXISTS)
593
594 # [126] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern
595 NotExistsFunc = Comp('Builtin_NOTEXISTS', Keyword('NOT') + Keyword(
596 'EXISTS') + Param('graph', GroupGraphPattern)).setEvalFn(op.Builtin_EXISTS)
597
598
599 # [127] Aggregate ::= 'COUNT' '(' 'DISTINCT'? ( '*' | Expression ) ')'
600 # | 'SUM' '(' Optional('DISTINCT') Expression ')'
601 # | 'MIN' '(' Optional('DISTINCT') Expression ')'
602 # | 'MAX' '(' Optional('DISTINCT') Expression ')'
603 # | 'AVG' '(' Optional('DISTINCT') Expression ')'
604 # | 'SAMPLE' '(' Optional('DISTINCT') Expression ')'
605 # | 'GROUP_CONCAT' '(' Optional('DISTINCT') Expression ( ';' 'SEPARATOR' '=' String )? ')'
606
607 _Distinct = Optional(Keyword('DISTINCT'))
608 _AggregateParams = '(' + Param(
609 'distinct', _Distinct) + Param('vars', Expression) + ')'
610
611 Aggregate = Comp('Aggregate_Count', Keyword('COUNT') + '(' + Param('distinct', _Distinct) + Param('vars', '*' | Expression) + ')')\
612 | Comp('Aggregate_Sum', Keyword('SUM') + _AggregateParams)\
613 | Comp('Aggregate_Min', Keyword('MIN') + _AggregateParams)\
614 | Comp('Aggregate_Max', Keyword('MAX') + _AggregateParams)\
615 | Comp('Aggregate_Avg', Keyword('AVG') + _AggregateParams)\
616 | Comp('Aggregate_Sample', Keyword('SAMPLE') + _AggregateParams)\
617 | Comp('Aggregate_GroupConcat', Keyword('GROUP_CONCAT') + '(' + Param('distinct', _Distinct) + Param('vars', Expression) + Optional(';' + Keyword('SEPARATOR') + '=' + Param('separator', String)) + ')')
618
619 # [121] BuiltInCall ::= Aggregate
620 # | 'STR' '(' + Expression + ')'
621 # | 'LANG' '(' + Expression + ')'
622 # | 'LANGMATCHES' '(' + Expression + ',' + Expression + ')'
623 # | 'DATATYPE' '(' + Expression + ')'
624 # | 'BOUND' '(' Var ')'
625 # | 'IRI' '(' + Expression + ')'
626 # | 'URI' '(' + Expression + ')'
627 # | 'BNODE' ( '(' + Expression + ')' | NIL )
628 # | 'RAND' NIL
629 # | 'ABS' '(' + Expression + ')'
630 # | 'CEIL' '(' + Expression + ')'
631 # | 'FLOOR' '(' + Expression + ')'
632 # | 'ROUND' '(' + Expression + ')'
633 # | 'CONCAT' ExpressionList
634 # | SubstringExpression
635 # | 'STRLEN' '(' + Expression + ')'
636 # | StrReplaceExpression
637 # | 'UCASE' '(' + Expression + ')'
638 # | 'LCASE' '(' + Expression + ')'
639 # | 'ENCODE_FOR_URI' '(' + Expression + ')'
640 # | 'CONTAINS' '(' + Expression + ',' + Expression + ')'
641 # | 'STRSTARTS' '(' + Expression + ',' + Expression + ')'
642 # | 'STRENDS' '(' + Expression + ',' + Expression + ')'
643 # | 'STRBEFORE' '(' + Expression + ',' + Expression + ')'
644 # | 'STRAFTER' '(' + Expression + ',' + Expression + ')'
645 # | 'YEAR' '(' + Expression + ')'
646 # | 'MONTH' '(' + Expression + ')'
647 # | 'DAY' '(' + Expression + ')'
648 # | 'HOURS' '(' + Expression + ')'
649 # | 'MINUTES' '(' + Expression + ')'
650 # | 'SECONDS' '(' + Expression + ')'
651 # | 'TIMEZONE' '(' + Expression + ')'
652 # | 'TZ' '(' + Expression + ')'
653 # | 'NOW' NIL
654 # | 'UUID' NIL
655 # | 'STRUUID' NIL
656 # | 'MD5' '(' + Expression + ')'
657 # | 'SHA1' '(' + Expression + ')'
658 # | 'SHA256' '(' + Expression + ')'
659 # | 'SHA384' '(' + Expression + ')'
660 # | 'SHA512' '(' + Expression + ')'
661 # | 'COALESCE' ExpressionList
662 # | 'IF' '(' Expression ',' Expression ',' Expression ')'
663 # | 'STRLANG' '(' + Expression + ',' + Expression + ')'
664 # | 'STRDT' '(' + Expression + ',' + Expression + ')'
665 # | 'sameTerm' '(' + Expression + ',' + Expression + ')'
666 # | 'isIRI' '(' + Expression + ')'
667 # | 'isURI' '(' + Expression + ')'
668 # | 'isBLANK' '(' + Expression + ')'
669 # | 'isLITERAL' '(' + Expression + ')'
670 # | 'isNUMERIC' '(' + Expression + ')'
671 # | RegexExpression
672 # | ExistsFunc
673 # | NotExistsFunc
674
675 BuiltInCall = Aggregate \
676 | Comp('Builtin_STR', Keyword('STR') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_STR) \
677 | Comp('Builtin_LANG', Keyword('LANG') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_LANG) \
678 | Comp('Builtin_LANGMATCHES', Keyword('LANGMATCHES') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_LANGMATCHES) \
679 | Comp('Builtin_DATATYPE', Keyword('DATATYPE') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_DATATYPE) \
680 | Comp('Builtin_BOUND', Keyword('BOUND') + '(' + Param('arg', Var) + ')').setEvalFn(op.Builtin_BOUND) \
681 | Comp('Builtin_IRI', Keyword('IRI') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_IRI) \
682 | Comp('Builtin_URI', Keyword('URI') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_IRI) \
683 | Comp('Builtin_BNODE', Keyword('BNODE') + ('(' + Param('arg', Expression) + ')' | NIL)).setEvalFn(op.Builtin_BNODE) \
684 | Comp('Builtin_RAND', Keyword('RAND') + NIL).setEvalFn(op.Builtin_RAND) \
685 | Comp('Builtin_ABS', Keyword('ABS') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_ABS) \
686 | Comp('Builtin_CEIL', Keyword('CEIL') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_CEIL) \
687 | Comp('Builtin_FLOOR', Keyword('FLOOR') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_FLOOR) \
688 | Comp('Builtin_ROUND', Keyword('ROUND') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_ROUND) \
689 | Comp('Builtin_CONCAT', Keyword('CONCAT') + Param('arg', ExpressionList)).setEvalFn(op.Builtin_CONCAT) \
690 | SubstringExpression \
691 | Comp('Builtin_STRLEN', Keyword('STRLEN') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_STRLEN) \
692 | StrReplaceExpression \
693 | Comp('Builtin_UCASE', Keyword('UCASE') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_UCASE) \
694 | Comp('Builtin_LCASE', Keyword('LCASE') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_LCASE) \
695 | Comp('Builtin_ENCODE_FOR_URI', Keyword('ENCODE_FOR_URI') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_ENCODE_FOR_URI) \
696 | Comp('Builtin_CONTAINS', Keyword('CONTAINS') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_CONTAINS) \
697 | Comp('Builtin_STRSTARTS', Keyword('STRSTARTS') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRSTARTS) \
698 | Comp('Builtin_STRENDS', Keyword('STRENDS') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRENDS) \
699 | Comp('Builtin_STRBEFORE', Keyword('STRBEFORE') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRBEFORE) \
700 | Comp('Builtin_STRAFTER', Keyword('STRAFTER') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRAFTER) \
701 | Comp('Builtin_YEAR', Keyword('YEAR') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_YEAR) \
702 | Comp('Builtin_MONTH', Keyword('MONTH') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_MONTH) \
703 | Comp('Builtin_DAY', Keyword('DAY') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_DAY) \
704 | Comp('Builtin_HOURS', Keyword('HOURS') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_HOURS) \
705 | Comp('Builtin_MINUTES', Keyword('MINUTES') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_MINUTES) \
706 | Comp('Builtin_SECONDS', Keyword('SECONDS') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_SECONDS) \
707 | Comp('Builtin_TIMEZONE', Keyword('TIMEZONE') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_TIMEZONE) \
708 | Comp('Builtin_TZ', Keyword('TZ') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_TZ) \
709 | Comp('Builtin_NOW', Keyword('NOW') + NIL).setEvalFn(op.Builtin_NOW) \
710 | Comp('Builtin_UUID', Keyword('UUID') + NIL).setEvalFn(op.Builtin_UUID) \
711 | Comp('Builtin_STRUUID', Keyword('STRUUID') + NIL).setEvalFn(op.Builtin_STRUUID) \
712 | Comp('Builtin_MD5', Keyword('MD5') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_MD5) \
713 | Comp('Builtin_SHA1', Keyword('SHA1') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_SHA1) \
714 | Comp('Builtin_SHA256', Keyword('SHA256') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_SHA256) \
715 | Comp('Builtin_SHA384', Keyword('SHA384') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_SHA384) \
716 | Comp('Builtin_SHA512', Keyword('SHA512') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_SHA512) \
717 | Comp('Builtin_COALESCE', Keyword('COALESCE') + Param('arg', ExpressionList)).setEvalFn(op.Builtin_COALESCE) \
718 | Comp('Builtin_IF', Keyword('IF') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ',' + Param('arg3', Expression) + ')').setEvalFn(op.Builtin_IF) \
719 | Comp('Builtin_STRLANG', Keyword('STRLANG') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRLANG) \
720 | Comp('Builtin_STRDT', Keyword('STRDT') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_STRDT) \
721 | Comp('Builtin_sameTerm', Keyword('sameTerm') + '(' + Param('arg1', Expression) + ',' + Param('arg2', Expression) + ')').setEvalFn(op.Builtin_sameTerm) \
722 | Comp('Builtin_isIRI', Keyword('isIRI') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_isIRI) \
723 | Comp('Builtin_isURI', Keyword('isURI') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_isIRI) \
724 | Comp('Builtin_isBLANK', Keyword('isBLANK') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_isBLANK) \
725 | Comp('Builtin_isLITERAL', Keyword('isLITERAL') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_isLITERAL) \
726 | Comp('Builtin_isNUMERIC', Keyword('isNUMERIC') + '(' + Param('arg', Expression) + ')').setEvalFn(op.Builtin_isNUMERIC) \
727 | RegexExpression \
728 | ExistsFunc \
729 | NotExistsFunc
730
731 # [71] ArgList ::= NIL | '(' 'DISTINCT'? Expression ( ',' Expression )* ')'
732 ArgList = NIL | '(' + Param('distinct', _Distinct) + delimitedList(
733 ParamList('expr', Expression)) + ')'
734
735 # [128] iriOrFunction ::= iri Optional(ArgList)
736 iriOrFunction = (Comp(
737 'Function', Param('iri', iri) + ArgList).setEvalFn(op.Function)) | iri
738
739 # [70] FunctionCall ::= iri ArgList
740 FunctionCall = Comp(
741 'Function', Param('iri', iri) + ArgList).setEvalFn(op.Function)
742
743
744 # [120] BrackettedExpression ::= '(' Expression ')'
745 BrackettedExpression = Suppress('(') + Expression + Suppress(')')
746
747 # [119] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var
748 PrimaryExpression = BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var
749
750 # [118] UnaryExpression ::= '!' PrimaryExpression
751 # | '+' PrimaryExpression
752 # | '-' PrimaryExpression
753 # | PrimaryExpression
754 UnaryExpression = Comp('UnaryNot', '!' + Param('expr', PrimaryExpression)).setEvalFn(op.UnaryNot) \
755 | Comp('UnaryPlus', '+' + Param('expr', PrimaryExpression)).setEvalFn(op.UnaryPlus) \
756 | Comp('UnaryMinus', '-' + Param('expr', PrimaryExpression)).setEvalFn(op.UnaryMinus) \
757 | PrimaryExpression
758
759 # [117] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
760 MultiplicativeExpression = Comp('MultiplicativeExpression', Param('expr', UnaryExpression) + ZeroOrMore(ParamList('op', '*') + ParamList(
761 'other', UnaryExpression) | ParamList('op', '/') + ParamList('other', UnaryExpression))).setEvalFn(op.MultiplicativeExpression)
762
763 # [116] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
764
765 ### NOTE: The second part of this production is there because:
766 ### "In signed numbers, no white space is allowed between the sign and the number. The AdditiveExpression grammar rule allows for this by covering the two cases of an expression followed by a signed number. These produce an addition or subtraction of the unsigned number as appropriate."
767
768 # Here (I think) this is not nescessary since pyparsing doesn't separate
769 # tokenizing and parsing
770
771
772 AdditiveExpression = Comp('AdditiveExpression', Param('expr', MultiplicativeExpression) +
773 ZeroOrMore(ParamList('op', '+') + ParamList('other', MultiplicativeExpression) |
774 ParamList('op', '-') + ParamList('other', MultiplicativeExpression))).setEvalFn(op.AdditiveExpression)
775
776
777 # [115] NumericExpression ::= AdditiveExpression
778 NumericExpression = AdditiveExpression
779
780 # [114] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
781 RelationalExpression = Comp('RelationalExpression', Param('expr', NumericExpression) + Optional(
782 Param('op', '=') + Param('other', NumericExpression) |
783 Param('op', '!=') + Param('other', NumericExpression) |
784 Param('op', '<') + Param('other', NumericExpression) |
785 Param('op', '>') + Param('other', NumericExpression) |
786 Param('op', '<=') + Param('other', NumericExpression) |
787 Param('op', '>=') + Param('other', NumericExpression) |
788 Param('op', Keyword('IN')) + Param('other', ExpressionList) |
789 Param('op', Combine(Keyword('NOT') + Keyword('IN'), adjacent=False, joinString=" ")) + Param('other', ExpressionList))).setEvalFn(op.RelationalExpression)
790
791
792 # [113] ValueLogical ::= RelationalExpression
793 ValueLogical = RelationalExpression
794
795 # [112] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )*
796 ConditionalAndExpression = Comp('ConditionalAndExpression', Param('expr', ValueLogical) + ZeroOrMore(
797 '&&' + ParamList('other', ValueLogical))).setEvalFn(op.ConditionalAndExpression)
798
799 # [111] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )*
800 ConditionalOrExpression = Comp('ConditionalOrExpression', Param('expr', ConditionalAndExpression) + ZeroOrMore(
801 '||' + ParamList('other', ConditionalAndExpression))).setEvalFn(op.ConditionalOrExpression)
802
803 # [110] Expression ::= ConditionalOrExpression
804 Expression << ConditionalOrExpression
805
806
807 # [69] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall
808 Constraint = BrackettedExpression | BuiltInCall | FunctionCall
809
810 # [68] Filter ::= 'FILTER' Constraint
811 Filter = Comp('Filter', Keyword('FILTER') + Param('expr', Constraint))
812
813
814 # [16] SourceSelector ::= iri
815 SourceSelector = iri
816
817 # [14] DefaultGraphClause ::= SourceSelector
818 DefaultGraphClause = SourceSelector
819
820 # [15] NamedGraphClause ::= 'NAMED' SourceSelector
821 NamedGraphClause = Keyword('NAMED') + Param('named', SourceSelector)
822
823 # [13] DatasetClause ::= 'FROM' ( DefaultGraphClause | NamedGraphClause )
824 DatasetClause = Comp('DatasetClause', Keyword(
825 'FROM') + (Param('default', DefaultGraphClause) | NamedGraphClause))
826
827 # [20] GroupCondition ::= BuiltInCall | FunctionCall | '(' Expression ( 'AS' Var )? ')' | Var
828 GroupCondition = BuiltInCall | FunctionCall | Comp('GroupAs', '(' + Param(
829 'expr', Expression) + Optional(Keyword('AS') + Param('var', Var)) + ')') | Var
830
831 # [19] GroupClause ::= 'GROUP' 'BY' GroupCondition+
832 GroupClause = Comp('GroupClause', Keyword('GROUP') + Keyword(
833 'BY') + OneOrMore(ParamList('condition', GroupCondition)))
834
835
836 _Silent = Optional(Param('silent', Keyword('SILENT')))
837
838 # [31] Load ::= 'LOAD' 'SILENT'? iri ( 'INTO' GraphRef )?
839 Load = Comp('Load', Keyword('LOAD') + _Silent + Param('iri', iri) +
840 Optional(Keyword('INTO') + GraphRef))
841
842 # [32] Clear ::= 'CLEAR' 'SILENT'? GraphRefAll
843 Clear = Comp('Clear', Keyword('CLEAR') + _Silent + GraphRefAll)
844
845 # [33] Drop ::= 'DROP' _Silent GraphRefAll
846 Drop = Comp('Drop', Keyword('DROP') + _Silent + GraphRefAll)
847
848 # [34] Create ::= 'CREATE' _Silent GraphRef
849 Create = Comp('Create', Keyword('CREATE') + _Silent + GraphRef)
850
851 # [35] Add ::= 'ADD' _Silent GraphOrDefault 'TO' GraphOrDefault
852 Add = Comp('Add', Keyword(
853 'ADD') + _Silent + GraphOrDefault + Keyword('TO') + GraphOrDefault)
854
855 # [36] Move ::= 'MOVE' _Silent GraphOrDefault 'TO' GraphOrDefault
856 Move = Comp('Move', Keyword(
857 'MOVE') + _Silent + GraphOrDefault + Keyword('TO') + GraphOrDefault)
858
859 # [37] Copy ::= 'COPY' _Silent GraphOrDefault 'TO' GraphOrDefault
860 Copy = Comp('Copy', Keyword(
861 'COPY') + _Silent + GraphOrDefault + Keyword('TO') + GraphOrDefault)
862
863 # [38] InsertData ::= 'INSERT DATA' QuadData
864 InsertData = Comp('InsertData', Keyword('INSERT') + Keyword('DATA') + QuadData)
865
866 # [39] DeleteData ::= 'DELETE DATA' QuadData
867 DeleteData = Comp('DeleteData', Keyword('DELETE') + Keyword('DATA') + QuadData)
868
869 # [40] DeleteWhere ::= 'DELETE WHERE' QuadPattern
870 DeleteWhere = Comp(
871 'DeleteWhere', Keyword('DELETE') + Keyword('WHERE') + QuadPattern)
872
873 # [42] DeleteClause ::= 'DELETE' QuadPattern
874 DeleteClause = Comp('DeleteClause', Keyword('DELETE') + QuadPattern)
875
876 # [43] InsertClause ::= 'INSERT' QuadPattern
877 InsertClause = Comp('InsertClause', Keyword('INSERT') + QuadPattern)
878
879 # [44] UsingClause ::= 'USING' ( iri | 'NAMED' iri )
880 UsingClause = Comp('UsingClause', Keyword('USING') + (
881 Param('default', iri) | Keyword('NAMED') + Param('named', iri)))
882
883 # [41] Modify ::= ( 'WITH' iri )? ( DeleteClause Optional(InsertClause) | InsertClause ) ZeroOrMore(UsingClause) 'WHERE' GroupGraphPattern
884 Modify = Comp('Modify', Optional(Keyword('WITH') + Param('withClause', iri)) + (Param('delete', DeleteClause) + Optional(Param(
885 'insert', InsertClause)) | Param('insert', InsertClause)) + ZeroOrMore(ParamList('using', UsingClause)) + Keyword('WHERE') + Param('where', GroupGraphPattern))
886
887
888 # [30] Update1 ::= Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify
889 Update1 = Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify
890
891
892 # [63] InlineDataOneVar ::= Var '{' ZeroOrMore(DataBlockValue) '}'
893 InlineDataOneVar = ParamList(
894 'var', Var) + '{' + ZeroOrMore(ParamList('value', DataBlockValue)) + '}'
895
896 # [64] InlineDataFull ::= ( NIL | '(' ZeroOrMore(Var) ')' ) '{' ( '(' ZeroOrMore(DataBlockValue) ')' | NIL )* '}'
897 InlineDataFull = (NIL | '(' + ZeroOrMore(ParamList('var', Var)) + ')') + '{' + ZeroOrMore(
898 ParamList('value', Group(Suppress('(') + ZeroOrMore(DataBlockValue) + Suppress(')') | NIL))) + '}'
899
900 # [62] DataBlock ::= InlineDataOneVar | InlineDataFull
901 DataBlock = InlineDataOneVar | InlineDataFull
902
903
904 # [28] ValuesClause ::= ( 'VALUES' DataBlock )?
905 ValuesClause = Optional(Param(
906 'valuesClause', Comp('ValuesClause', Keyword('VALUES') + DataBlock)))
907
908
909 # [74] ConstructTriples ::= TriplesSameSubject ( '.' Optional(ConstructTriples) )?
910 ConstructTriples = Forward()
911 ConstructTriples << (ParamList('template', TriplesSameSubject) + Optional(
912 Suppress('.') + Optional(ConstructTriples)))
913
914 # [73] ConstructTemplate ::= '{' Optional(ConstructTriples) '}'
915 ConstructTemplate = Suppress('{') + Optional(ConstructTriples) + Suppress('}')
916
917
918 # [57] OptionalGraphPattern ::= 'OPTIONAL' GroupGraphPattern
919 OptionalGraphPattern = Comp('OptionalGraphPattern', Keyword(
920 'OPTIONAL') + Param('graph', GroupGraphPattern))
921
922 # [58] GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern
923 GraphGraphPattern = Comp('GraphGraphPattern', Keyword(
924 'GRAPH') + Param('term', VarOrIri) + Param('graph', GroupGraphPattern))
925
926 # [59] ServiceGraphPattern ::= 'SERVICE' _Silent VarOrIri GroupGraphPattern
927 ServiceGraphPattern = Comp('ServiceGraphPattern', Keyword(
928 'SERVICE') + _Silent + Param('term', VarOrIri) + Param('graph', GroupGraphPattern))
929
930 # [60] Bind ::= 'BIND' '(' Expression 'AS' Var ')'
931 Bind = Comp('Bind', Keyword('BIND') + '(' + Param(
932 'expr', Expression) + Keyword('AS') + Param('var', Var) + ')')
933
934 # [61] InlineData ::= 'VALUES' DataBlock
935 InlineData = Comp('InlineData', Keyword('VALUES') + DataBlock)
936
937 # [56] GraphPatternNotTriples ::= GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData
938 GraphPatternNotTriples = GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData
939
940 # [54] GroupGraphPatternSub ::= Optional(TriplesBlock) ( GraphPatternNotTriples '.'? Optional(TriplesBlock) )*
941 GroupGraphPatternSub = Comp('GroupGraphPatternSub', Optional(ParamList('part', Comp('TriplesBlock', TriplesBlock))) + ZeroOrMore(
942 ParamList('part', GraphPatternNotTriples) + Optional('.') + Optional(ParamList('part', Comp('TriplesBlock', TriplesBlock)))))
943
944
945 # ----------------
946 # [22] HavingCondition ::= Constraint
947 HavingCondition = Constraint
948
949 # [21] HavingClause ::= 'HAVING' HavingCondition+
950 HavingClause = Comp('HavingClause', Keyword(
951 'HAVING') + OneOrMore(ParamList('condition', HavingCondition)))
952
953 # [24] OrderCondition ::= ( ( 'ASC' | 'DESC' ) BrackettedExpression )
954 # | ( Constraint | Var )
955 OrderCondition = Comp('OrderCondition', Param('order', Keyword('ASC') | Keyword(
956 'DESC')) + Param('expr', BrackettedExpression) | Param('expr', Constraint | Var))
957
958 # [23] OrderClause ::= 'ORDER' 'BY' OneOrMore(OrderCondition)
959 OrderClause = Comp('OrderClause', Keyword('ORDER') + Keyword(
960 'BY') + OneOrMore(ParamList('condition', OrderCondition)))
961
962 # [26] LimitClause ::= 'LIMIT' INTEGER
963 LimitClause = Keyword('LIMIT') + Param('limit', INTEGER)
964
965 # [27] OffsetClause ::= 'OFFSET' INTEGER
966 OffsetClause = Keyword('OFFSET') + Param('offset', INTEGER)
967
968 # [25] LimitOffsetClauses ::= LimitClause Optional(OffsetClause) | OffsetClause Optional(LimitClause)
969 LimitOffsetClauses = Comp('LimitOffsetClauses', LimitClause + Optional(
970 OffsetClause) | OffsetClause + Optional(LimitClause))
971
972 # [18] SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses?
973 SolutionModifier = Optional(Param('groupby', GroupClause)) + Optional(Param('having', HavingClause)) + Optional(
974 Param('orderby', OrderClause)) + Optional(Param('limitoffset', LimitOffsetClauses))
975
976
977 # [9] SelectClause ::= 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '(' Expression 'AS' Var ')' ) )+ | '*' )
978 SelectClause = Keyword('SELECT') + Optional(Param('modifier', Keyword('DISTINCT') | Keyword('REDUCED'))) + (OneOrMore(ParamList('projection', Comp('vars',
979 Param('var', Var) | (Literal('(') + Param('expr', Expression) + Keyword('AS') + Param('evar', Var) + ')')))) | '*')
980
981 # [17] WhereClause ::= 'WHERE'? GroupGraphPattern
982 WhereClause = Optional(Keyword('WHERE')) + Param('where', GroupGraphPattern)
983
984 # [8] SubSelect ::= SelectClause WhereClause SolutionModifier ValuesClause
985 SubSelect = Comp('SubSelect', SelectClause + WhereClause +
986 SolutionModifier + ValuesClause)
987
988 # [53] GroupGraphPattern ::= '{' ( SubSelect | GroupGraphPatternSub ) '}'
989 GroupGraphPattern << (
990 Suppress('{') + (SubSelect | GroupGraphPatternSub) + Suppress('}'))
991
992 # [7] SelectQuery ::= SelectClause DatasetClause* WhereClause SolutionModifier
993 SelectQuery = Comp('SelectQuery', SelectClause + ZeroOrMore(ParamList(
994 'datasetClause', DatasetClause)) + WhereClause + SolutionModifier + ValuesClause)
995
996 # [10] ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier )
997 # NOTE: The CONSTRUCT WHERE alternative has unnescessarily many Comp/Param pairs
998 # to allow it to through the same algebra translation process
999 ConstructQuery = Comp('ConstructQuery', Keyword('CONSTRUCT') + (ConstructTemplate + ZeroOrMore(ParamList('datasetClause', DatasetClause)) + WhereClause + SolutionModifier + ValuesClause | ZeroOrMore(ParamList(
1000 'datasetClause', DatasetClause)) + Keyword('WHERE') + '{' + Optional(Param('where', Comp('FakeGroupGraphPatten', ParamList('part', Comp('TriplesBlock', TriplesTemplate))))) + '}' + SolutionModifier + ValuesClause))
1001
1002 # [12] AskQuery ::= 'ASK' DatasetClause* WhereClause SolutionModifier
1003 AskQuery = Comp('AskQuery', Keyword('ASK') + Param('datasetClause', ZeroOrMore(
1004 DatasetClause)) + WhereClause + SolutionModifier + ValuesClause)
1005
1006 # [11] DescribeQuery ::= 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier
1007 DescribeQuery = Comp('DescribeQuery', Keyword('DESCRIBE') + (OneOrMore(ParamList('var', VarOrIri)) | '*') + Param(
1008 'datasetClause', ZeroOrMore(DatasetClause)) + Optional(WhereClause) + SolutionModifier + ValuesClause)
1009
1010 # [29] Update ::= Prologue ( Update1 ( ';' Update )? )?
1011 Update = Forward()
1012 Update << (ParamList('prologue', Prologue) + Optional(ParamList('request',
1013 Update1) + Optional(';' + Update)))
1014
1015
1016 # [2] Query ::= Prologue
1017 # ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery )
1018 # ValuesClause
1019 # NOTE: ValuesClause was moved to invidual queries
1020 Query = Prologue + (SelectQuery | ConstructQuery | DescribeQuery | AskQuery)
1021
1022 # [3] UpdateUnit ::= Update
1023 UpdateUnit = Comp('Update', Update)
1024
1025 # [1] QueryUnit ::= Query
1026 QueryUnit = Query
1027
1028 QueryUnit.ignore('#' + restOfLine)
1029 UpdateUnit.ignore('#' + restOfLine)
1030
1031
1032 expandUnicodeEscapes_re = re.compile(
1033 r'\\u([0-9a-f]{4}(?:[0-9a-f]{4})?)', flags=re.I)
1034
1035
1036 def expandUnicodeEscapes(q):
1037 """
1038 The syntax of the SPARQL Query Language is expressed over code points in Unicode [UNICODE]. The encoding is always UTF-8 [RFC3629].
1039 Unicode code points may also be expressed using an \ uXXXX (U+0 to U+FFFF) or \ UXXXXXXXX syntax (for U+10000 onwards) where X is a hexadecimal digit [0-9A-F]
1040 """
1041
1042 def expand(m):
1043 try:
1044 return chr(int(m.group(1), 16))
1045 except:
1046 raise Exception("Invalid unicode code point: " + m)
1047
1048 return expandUnicodeEscapes_re.sub(expand, q)
1049
1050
1051 def parseQuery(q):
1052 if hasattr(q, 'read'):
1053 q = q.read()
1054 if isinstance(q, bytestype):
1055 q = q.decode('utf-8')
1056
1057 q = expandUnicodeEscapes(q)
1058 return Query.parseString(q, parseAll=True)
1059
1060
1061 def parseUpdate(q):
1062 if hasattr(q, 'read'):
1063 q = q.read()
1064
1065 if isinstance(q, bytestype):
1066 q = q.decode('utf-8')
1067
1068 q = expandUnicodeEscapes(q)
1069 return UpdateUnit.parseString(q, parseAll=True)[0]
1070
1071
1072 if __name__ == '__main__':
1073 import sys
1074 DEBUG = True
1075 try:
1076 q = Query.parseString(sys.argv[1])
1077 print("\nSyntax Tree:\n")
1078 print(q)
1079 except ParseException as err:
1080 print(err.line)
1081 print(" " * (err.column - 1) + "^")
1082 print(err)