sparql 3.3.1 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3115 @@
1
+ require 'ebnf'
2
+ require 'ebnf/peg/parser'
3
+ require 'sparql/grammar/meta'
4
+
5
+ module SPARQL::Grammar
6
+ ##
7
+ # A parser for the SPARQL 1.1 grammar.
8
+ #
9
+ # @see https://www.w3.org/TR/sparql11-query/#grammar
10
+ # @see https://en.wikipedia.org/wiki/LR_parser
11
+ class Parser
12
+ include SPARQL::Grammar::Meta
13
+ include SPARQL::Grammar::Terminals
14
+ include EBNF::PEG::Parser
15
+
16
+ ##
17
+ # Any additional options for the parser.
18
+ #
19
+ # @return [Hash]
20
+ attr_reader :options
21
+
22
+ ##
23
+ # The current input string being processed.
24
+ #
25
+ # @return [String]
26
+ attr_accessor :input
27
+
28
+ ##
29
+ # The internal representation of the result using hierarchy of RDF objects and SPARQL::Algebra::Operator
30
+ # objects.
31
+ # @return [Array]
32
+ attr_accessor :result
33
+
34
+ # Terminals passed to lexer. Order matters!
35
+ terminal(:ANON, ANON) do |value, prod|
36
+ bnode
37
+ end
38
+ terminal(:NIL, NIL) do |value, prod|
39
+ RDF['nil']
40
+ end
41
+ terminal(:BLANK_NODE_LABEL, BLANK_NODE_LABEL) do |value, prod|
42
+ bnode(value[2..-1])
43
+ end
44
+ terminal(:IRIREF, IRIREF) do |value, prod|
45
+ begin
46
+ iri(value[1..-2])
47
+ rescue ArgumentError => e
48
+ raise Error, e.message
49
+ end
50
+ end
51
+ terminal(:DOUBLE_POSITIVE, DOUBLE_POSITIVE) do |value, prod|
52
+ # Note that a Turtle Double may begin with a '.[eE]', so tack on a leading
53
+ # zero if necessary
54
+ value = value.sub(/\.([eE])/, '.0\1')
55
+ literal(value, datatype: RDF::XSD.double)
56
+ end
57
+ terminal(:DECIMAL_POSITIVE, DECIMAL_POSITIVE) do |value, prod|
58
+ # Note that a Turtle Decimal may begin with a '.', so tack on a leading
59
+ # zero if necessary
60
+ value = "0#{value}" if value[0,1] == "."
61
+ literal(value, datatype: RDF::XSD.decimal)
62
+ end
63
+ terminal(:INTEGER_POSITIVE, INTEGER_POSITIVE) do |value, prod|
64
+ literal(value, datatype: RDF::XSD.integer)
65
+ end
66
+ terminal(:DOUBLE_NEGATIVE, DOUBLE_NEGATIVE) do |value, prod|
67
+ # Note that a Turtle Double may begin with a '.[eE]', so tack on a leading
68
+ # zero if necessary
69
+ value = value.sub(/\.([eE])/, '.0\1')
70
+ literal(value, datatype: RDF::XSD.double)
71
+ end
72
+ terminal(:DECIMAL_NEGATIVE, DECIMAL_NEGATIVE) do |value, prod|
73
+ # Note that a Turtle Decimal may begin with a '.', so tack on a leading
74
+ # zero if necessary
75
+ value = "0#{value}" if value[0,1] == "."
76
+ literal(value, datatype: RDF::XSD.decimal)
77
+ end
78
+ terminal(:INTEGER_NEGATIVE, INTEGER_NEGATIVE) do |value, prod|
79
+ literal(value, datatype: RDF::XSD.integer)
80
+ end
81
+ terminal(:DOUBLE, DOUBLE) do |value, prod|
82
+ # Note that a Turtle Double may begin with a '.[eE]', so tack on a leading
83
+ # zero if necessary
84
+ value = value.sub(/\.([eE])/, '.0\1')
85
+ literal(value, datatype: RDF::XSD.double)
86
+ end
87
+ terminal(:DECIMAL, DECIMAL) do |value, prod|
88
+ # Note that a Turtle Decimal may begin with a '.', so tack on a leading
89
+ # zero if necessary
90
+ value = value
91
+ #value = "0#{value}" if value[0,1] == "."
92
+ literal(value, datatype: RDF::XSD.decimal)
93
+ end
94
+ terminal(:INTEGER, INTEGER) do |value, prod|
95
+ literal(value, datatype: RDF::XSD.integer)
96
+ end
97
+ terminal(:LANG_DIR, LANG_DIR) do |value, prod|
98
+ value[1..-1]
99
+ end
100
+ terminal(:PNAME_LN, PNAME_LN, unescape: true) do |value, prod|
101
+ prefix, suffix = value.split(":", 2)
102
+ ns(prefix, suffix)
103
+ end
104
+ terminal(:PNAME_NS, PNAME_NS) do |value, prod|
105
+ value[0..-2].to_sym
106
+ end
107
+ terminal(:STRING_LITERAL_LONG1, STRING_LITERAL_LONG1, unescape: true) do |value, prod|
108
+ value[3..-4]
109
+ end
110
+ terminal(:STRING_LITERAL_LONG2, STRING_LITERAL_LONG2, unescape: true) do |value, prod|
111
+ value[3..-4]
112
+ end
113
+ terminal(:STRING_LITERAL1, STRING_LITERAL1, unescape: true) do |value, prod|
114
+ value[1..-2]
115
+ end
116
+ terminal(:STRING_LITERAL2, STRING_LITERAL2, unescape: true) do |value, prod|
117
+ value[1..-2]
118
+ end
119
+ terminal(:VAR1, VAR1) do |value, prod|
120
+ variable(value[1..-1])
121
+ end
122
+ terminal(:VAR2, VAR2) do |value, prod|
123
+ variable(value[1..-1])
124
+ end
125
+
126
+ # Productions
127
+
128
+ # Query ::= Prologue ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery )
129
+ #
130
+ # Inputs from value include :Prologe and :_Query_1
131
+ # Result is query
132
+ start_production(:Query, as_hash: true)
133
+ production(:Query) do |value|
134
+ query = value[:_Query_1]
135
+ prologue = value[:Prologue] || {PrefixDecl: []}
136
+
137
+ # Add prefix
138
+ unless prologue[:PrefixDecl].empty?
139
+ pfx = prologue[:PrefixDecl].shift
140
+ prologue[:PrefixDecl].each {|p| pfx.merge!(p)}
141
+ pfx.operands[1] = query
142
+ query = pfx
143
+ end
144
+
145
+ # Add base
146
+ query = SPARQL::Algebra::Expression[:base, prologue[:BaseDecl], query] if prologue[:BaseDecl]
147
+
148
+ query
149
+ end
150
+
151
+ # UpdateUnit ::= Update
152
+ #
153
+ # Result is update
154
+ start_production(:UpdateUnit, as_hash: true)
155
+ production(:UpdateUnit) do |value|
156
+ value[:Update]
157
+ end
158
+
159
+ # Prologue ::= ( BaseDecl | PrefixDecl )*
160
+ #
161
+ # Inputs from value include :BaseDecl and :PrefixDecl
162
+ # Result is hash including BaseDecl and PrefixDecl
163
+ production(:Prologue) do |value|
164
+ unless resolve_iris?
165
+ # Only output if we're not resolving URIs internally
166
+ {
167
+ BaseDecl: value.map {|v| v[:BaseDecl]}.compact.last,
168
+ PrefixDecl: value.map {|v| v[:PrefixDecl]}.compact
169
+ }.compact
170
+ end
171
+ end
172
+
173
+ # BaseDecl ::= 'BASE' IRIREF
174
+ #
175
+ # Inputs from value includes :IRIREF
176
+ # Result is hash including BaseDecl, unless we are resolving IRIs
177
+ start_production(:BaseDecl, as_hash: true, insensitive_srings: :upper)
178
+ production(:BaseDecl) do |value|
179
+ iri = value[:IRIREF]
180
+ debug("BaseDecl") {"Defined base as #{iri}"}
181
+ self.base_uri = iri(iri)
182
+ resolve_iris? || {BaseDecl: iri}
183
+ end
184
+
185
+ # PrefixDecl ::= 'PREFIX' PNAME_NS IRIREF
186
+ #
187
+ # Inputs from value include :PNAME_NS and :IRIREF
188
+ # Result is hash including PrefixDecl
189
+ start_production(:PrefixDecl, as_hash: true, insensitive_srings: :upper)
190
+ production(:PrefixDecl) do |value|
191
+ pfx = value[:PNAME_NS]
192
+ self.prefix(pfx, value[:IRIREF])
193
+ prefix_op = SPARQL::Algebra::Operator::Prefix.new([["#{pfx}:".to_sym, value[:IRIREF]]], [])
194
+ {PrefixDecl: prefix_op}
195
+ end
196
+
197
+ # SelectQuery ::= SelectClause DatasetClause* WhereClause SolutionModifier ValuesClause
198
+ #
199
+ # Inputs are dataset, query, values, solution modifiers, vars, and extensions.
200
+ # Result is a query
201
+ start_production(:SelectQuery, as_hash: true)
202
+ production(:SelectQuery) do |value|
203
+ modifiers = {
204
+ dataset: value[:_SelectQuery_1],
205
+ query: value[:WhereClause][:query],
206
+ values: value[:ValuesClause],
207
+ }.merge(value[:SolutionModifier]).merge(value[:SelectClause])
208
+ merge_modifiers(modifiers)
209
+ end
210
+
211
+ # SubSelect ::= SelectClause WhereClause SolutionModifier
212
+ #
213
+ # Inputs are query, solution modifiers, vars, and extensions.
214
+ # Result is a hash including query.
215
+ start_production(:SubSelect, as_hash: true)
216
+ production(:SubSelect) do |value|
217
+ modifiers = value[:WhereClause].merge(value[:SolutionModifier]).merge(value[:SelectClause])
218
+ query = merge_modifiers(modifiers)
219
+ {query: query}
220
+ end
221
+
222
+ # SelectClause ::= 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '(' Expression 'AS' Var ')' ) )+ | '*' )
223
+ #
224
+ # (rule SelectClause (seq 'SELECT' _SelectClause_1 _SelectClause_2))
225
+ # (rule _SelectClause_1 (opt _SelectClause_3))
226
+ # (rule _SelectClause_3 (alt 'DISTINCT' 'REDUCED'))
227
+ # (rule _SelectClause_2 (alt _SelectClause_4 '*'))
228
+ # (rule _SelectClause_4 (plus _SelectClause_5))
229
+ # (rule _SelectClause_5 (alt Var _SelectClause_6))
230
+ # (rule _SelectClause_6 (seq '(' Expression 'AS' Var ')'))
231
+ #
232
+ # Inputs from value includes :_SelectClause_2 (a list of :variables and extensions).
233
+ # Result is a hash including distinct/reduced, vars and extensions.
234
+ start_production(:SelectClause, as_hash: true)
235
+ production(:SelectClause) do |value|
236
+ res = {
237
+ DISTINCT_REDUCED: value[:_SelectClause_1]
238
+ }
239
+
240
+ sc2 = Array(value[:_SelectClause_2])
241
+ sc2.each do |expr|
242
+ if expr == '*'
243
+ res[:Var] = %w(*)
244
+ elsif expr.is_a?(RDF::Query::Variable)
245
+ (res[:Var] ||= []) << expr
246
+ elsif expr.is_a?(Hash) && expr[:extend]
247
+ (res[:extend] ||= []) << expr[:extend]
248
+ end
249
+ end
250
+
251
+ res
252
+ end
253
+
254
+ # (rule _SelectClause_6 (seq '(' Expression 'AS' Var ')'))
255
+ start_production(:_SelectClause_6, as_hash: true)
256
+ production(:_SelectClause_6) do |value|
257
+ {extend: [value[:Var], value[:Expression]]}
258
+ end
259
+
260
+ # ConstructQuery ::= 'CONSTRUCT'
261
+ # ( ConstructTemplate
262
+ # DatasetClause*
263
+ # WhereClause
264
+ # SolutionModifier | DatasetClause*
265
+ # 'WHERE' '{' TriplesTemplate? '}'
266
+ # SolutionModifier
267
+ # )
268
+ # ValuesClause
269
+ #
270
+ # (rule ConstructQuery (seq 'CONSTRUCT' _ConstructQuery_1 ValuesClause))
271
+ # (rule _ConstructQuery_1 (alt _ConstructQuery_2 _ConstructQuery_3))
272
+ # (rule _ConstructQuery_2
273
+ # (seq ConstructTemplate _ConstructQuery_4 WhereClause SolutionModifier))
274
+ # (rule _ConstructQuery_4 (star DatasetClause))
275
+ # (rule _ConstructQuery_3
276
+ # (seq _ConstructQuery_5 'WHERE' '{' _ConstructQuery_6 '}' SolutionModifier))
277
+ # (rule _ConstructQuery_5 (star DatasetClause))
278
+ # (rule _ConstructQuery_6 (opt TriplesTemplate))
279
+ #
280
+ # Inputs from value includes :_ConstructQuery_1 (query modifiers) and :ValuesClause.
281
+ # Result is a query
282
+ start_production(:ConstructQuery, as_hash: true)
283
+ production(:ConstructQuery) do |value|
284
+ modifiers = value[:_ConstructQuery_1].merge(values: value[:ValuesClause])
285
+ template = modifiers.delete(:template) || []
286
+ query = merge_modifiers(modifiers)
287
+ SPARQL::Algebra::Expression[:construct, template, query]
288
+ end
289
+
290
+ # (rule _ConstructQuery_2
291
+ # (seq ConstructTemplate _ConstructQuery_4 WhereClause SolutionModifier))
292
+ start_production(:_ConstructQuery_2, as_hash: true)
293
+ production(:_ConstructQuery_2) do |value|
294
+ {
295
+ template: value[:ConstructTemplate],
296
+ dataset: value[:_ConstructQuery_4],
297
+ query: value[:WhereClause][:query]
298
+ }.merge(value[:SolutionModifier])
299
+ end
300
+
301
+ # (rule _ConstructQuery_3
302
+ # (seq _ConstructQuery_5 'WHERE' '{' _ConstructQuery_6 '}'
303
+ start_production(:_ConstructQuery_3, as_hash: true)
304
+ production(:_ConstructQuery_3) do |value|
305
+ {
306
+ template: value[:_ConstructQuery_6],
307
+ dataset: value[:_ConstructQuery_5],
308
+ query: SPARQL::Algebra::Operator::BGP.new(*value[:_ConstructQuery_6])
309
+ }.merge(value[:SolutionModifier])
310
+ end
311
+
312
+ # DescribeQuery ::= 'DESCRIBE' ( VarOrIri+ | '*' )
313
+ # DatasetClause* WhereClause? SolutionModifier ValuesClause
314
+ #
315
+ # Inputs from value includes dataset, query, values, and other merge modifiers.
316
+ # Result is a query
317
+ start_production(:DescribeQuery, as_hash: true)
318
+ production(:DescribeQuery) do |value|
319
+ modifiers = {
320
+ dataset: value[:_DescribeQuery_2],
321
+ query: value&.dig(:_DescribeQuery_3, :query),
322
+ values: value[:ValuesClause]
323
+ }.merge(value[:SolutionModifier])
324
+ query = merge_modifiers(modifiers)
325
+ to_describe = Array(value[:_DescribeQuery_1]).reject {|v| v == '*'}
326
+ SPARQL::Algebra::Expression[:describe, to_describe, query]
327
+ end
328
+
329
+ # AskQuery ::= 'ASK' DatasetClause* WhereClause ValuesClause
330
+ #
331
+ # Inputs from value includes dataset, query, values, and other merge modifiers.
332
+ # Result is a query
333
+ start_production(:AskQuery, as_hash: true)
334
+ production(:AskQuery) do |value|
335
+ modifiers = {
336
+ dataset: value[:_AskQuery_1],
337
+ query: value&.dig(:WhereClause, :query),
338
+ values: value[:ValuesClause]
339
+ }.merge(value[:SolutionModifier])
340
+ SPARQL::Algebra::Operator::Ask.new(merge_modifiers(modifiers))
341
+ end
342
+
343
+ # DatasetClause ::= 'FROM' ( DefaultGraphClause | NamedGraphClause )
344
+ start_production(:DatasetClause, as_hash: true, insenstive_strings: true)
345
+ production(:DatasetClause) do |value|
346
+ value[:_DatasetClause_1]
347
+ end
348
+
349
+ # DefaultGraphClause ::= SourceSelector
350
+ #
351
+ # Output is the source selector
352
+ production(:DefaultGraphClause) do |value|
353
+ value.first[:SourceSelector]
354
+ end
355
+
356
+ # NamedGraphClause ::= 'NAMED' SourceSelector
357
+ #
358
+ # Output is the named source selector.
359
+ start_production(:NamedGraphClause, as_hash: true)
360
+ production(:NamedGraphClause) do |value|
361
+ [:named, value[:SourceSelector]]
362
+ end
363
+
364
+ # SourceSelector ::= iri
365
+ production(:SourceSelector) do |value|
366
+ value.first[:iri]
367
+ end
368
+
369
+ # WhereClause ::= 'WHERE'? GroupGraphPattern
370
+ start_production(:WhereClause, as_hash: true)
371
+ production(:WhereClause) do |value|
372
+ {query: value&.dig(:GroupGraphPattern, :query)}
373
+ end
374
+
375
+ # SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses?
376
+ #
377
+ # Result is a query modifier including group, having, order, and slice.
378
+ start_production(:SolutionModifier, as_hash: true)
379
+ production(:SolutionModifier) do |value|
380
+ {
381
+ group: value[:_SolutionModifier_1],
382
+ having: value[:_SolutionModifier_2],
383
+ order: value[:_SolutionModifier_3],
384
+ slice: value[:_SolutionModifier_4],
385
+ }
386
+ end
387
+
388
+ # GroupClause ::= 'GROUP' 'BY' GroupCondition+
389
+ #
390
+ # Returns one or more group conditions
391
+ start_production(:GroupClause, as_hash: true)
392
+ production(:GroupClause) do |value|
393
+ value[:_GroupClause_1]
394
+ end
395
+
396
+ # GroupCondition ::= BuiltInCall | FunctionCall
397
+ # | '(' Expression ( 'AS' Var )? ')' | Var
398
+ #
399
+ # (rule GroupCondition (alt BuiltInCall FunctionCall _GroupCondition_1 Var))
400
+ # (rule _GroupCondition_1 (seq '(' Expression _GroupCondition_2 ')'))
401
+ # (rule _GroupCondition_2 (opt _GroupCondition_3))
402
+ # (rule _GroupCondition_3 (seq 'AS' Var))
403
+ #
404
+ # Result is an expression
405
+ start_production(:GroupCondition, as_hash: true)
406
+ production(:GroupCondition) do |value|
407
+ value
408
+ end
409
+
410
+ # _GroupCondition_1 ::= '(' Expression ( 'AS' Var )? ')'
411
+ #
412
+ # (rule _GroupCondition_1 (seq '(' Expression _GroupCondition_2 ')'))
413
+ # (rule _GroupCondition_2 (opt _GroupCondition_3))
414
+ # (rule _GroupCondition_3 (seq 'AS' Var))
415
+ #
416
+ # Returns the expression, or an array of the var and expression.
417
+ start_production(:_GroupCondition_1, as_hash: true)
418
+ production(:_GroupCondition_1) do |value|
419
+ if value[:_GroupCondition_2]
420
+ [value[:_GroupCondition_2], value[:Expression]]
421
+ else
422
+ value[:Expression]
423
+ end
424
+ end
425
+
426
+ production(:_GroupCondition_3) {|value| value.last[:Var]}
427
+
428
+ # HavingClause ::= 'HAVING' HavingCondition+
429
+ #
430
+ # (rule HavingClause (seq 'HAVING' _HavingClause_1))
431
+ # (rule _HavingClause_1 (plus HavingCondition))
432
+ start_production(:HavingClause, as_hash: true)
433
+ production(:HavingClause) do |value|
434
+ value[:_HavingClause_1]
435
+ end
436
+
437
+ # HavingCondition ::= Constraint
438
+ start_production(:HavingCondition, as_hash: true)
439
+ production(:HavingCondition) do |value|
440
+ value[:Constraint]
441
+ end
442
+
443
+ # OrderClause ::= 'ORDER' 'BY' OrderCondition+
444
+ start_production(:OrderClause, as_hash: true)
445
+ production(:OrderClause) do |value|
446
+ value[:_OrderClause_1]
447
+ end
448
+
449
+ # OrderCondition ::= ( ( 'ASC' | 'DESC' ) BrackettedExpression ) | ( Constraint | Var )
450
+ #
451
+ # (rule OrderCondition (alt _OrderCondition_1 _OrderCondition_2))
452
+ # (rule _OrderCondition_1 (seq _OrderCondition_3 BrackettedExpression))
453
+ # (rule _OrderCondition_3 (alt 'ASC' 'DESC'))
454
+ # (rule _OrderCondition_2 (alt Constraint Var))
455
+ start_production(:OrderCondition, as_hash: true)
456
+ production(:OrderCondition) do |value|
457
+ if value.is_a?(Hash) && value[:_OrderCondition_3]
458
+ SPARQL::Algebra::Expression(value[:_OrderCondition_3].downcase, value[:BrackettedExpression])
459
+ else
460
+ value
461
+ end
462
+ end
463
+ start_production(:_OrderCondition_1, as_hash: true)
464
+
465
+ # LimitOffsetClauses ::= LimitClause OffsetClause? | OffsetClause LimitClause?
466
+ #
467
+ # (rule _LimitOffsetClauses_1 (seq LimitClause _LimitOffsetClauses_3))
468
+ # (rule _LimitOffsetClauses_3 (opt OffsetClause))
469
+ # (rule _LimitOffsetClauses_2 (seq OffsetClause _LimitOffsetClauses_4))
470
+ # (rule _LimitOffsetClauses_4 (opt LimitClause))
471
+ production(:LimitOffsetClauses) do |value|
472
+ if value[:LimitClause]
473
+ if value[:_LimitOffsetClauses_3]
474
+ [value[:_LimitOffsetClauses_3], value[:LimitClause]]
475
+ else
476
+ [:_, value[:LimitClause]]
477
+ end
478
+ else
479
+ if value[:_LimitOffsetClauses_4]
480
+ [value[:OffsetClause], value[:_LimitOffsetClauses_4]]
481
+ else
482
+ [value[:OffsetClause], :_]
483
+ end
484
+ end
485
+ end
486
+ start_production(:_LimitOffsetClauses_1, as_hash: true)
487
+ start_production(:_LimitOffsetClauses_2, as_hash: true)
488
+
489
+ # LimitClause ::= 'LIMIT' INTEGER
490
+ start_production(:LimitClause, as_hash: true)
491
+ production(:LimitClause) do |value|
492
+ value[:INTEGER]
493
+ end
494
+
495
+ # OffsetClause ::= 'OFFSET' INTEGER
496
+ start_production(:OffsetClause, as_hash: true)
497
+ production(:OffsetClause) do |value|
498
+ value[:INTEGER]
499
+ end
500
+
501
+ # ValuesClause ::= ( 'VALUES' DataBlock )?
502
+ #
503
+ # Result is a table operator
504
+ start_production(:ValuesClause, as_hash: true)
505
+ production(:ValuesClause) do |value|
506
+ debug("ValuesClause") {value.inspect}
507
+ if value
508
+ args = [Array(value[:DataBlock][:Var]).unshift(:vars)] + value[:DataBlock][:row]
509
+ table = SPARQL::Algebra::Expression.for(:table, *args)
510
+ table
511
+ end
512
+ end
513
+
514
+ # Update ::= Prologue (Update1 (";" Update)? )?
515
+ #
516
+ # (rule Update (seq Prologue _Update_1))
517
+ # (rule _Update_1 (opt _Update_2))
518
+ # (rule _Update_2 (seq Update1 _Update_3))
519
+ # (rule _Update_3 (opt _Update_4))
520
+ # (rule _Update_4 (seq ';' Update))
521
+ #
522
+ # Output is algebra Expression
523
+ start_production(:Update, as_hash: true)
524
+ production(:Update) do |value|
525
+ prologue = value[:Prologue] || {PrefixDecl: []}
526
+ update = value[:_Update_1] || SPARQL::Algebra::Expression(:update)
527
+
528
+ # Add prefix
529
+ unless prologue[:PrefixDecl].empty?
530
+ pfx = prologue[:PrefixDecl].shift
531
+ prologue[:PrefixDecl].each {|p| pfx.merge!(p)}
532
+ pfx.operands[1] = update
533
+ update = pfx
534
+ end
535
+
536
+ # Add base
537
+ update = SPARQL::Algebra::Expression[:base, prologue[:BaseDecl], update] if prologue[:BaseDecl]
538
+ update
539
+ end
540
+
541
+ # (rule _Update_2 (seq Update1 _Update_3))
542
+ #
543
+ # Merges update operators
544
+ #
545
+ # Returns an update operator
546
+ start_production(:_Update_2, as_hash: true)
547
+ production(:_Update_2) do |value|
548
+ if value[:_Update_3]
549
+ SPARQL::Algebra::Expression(:update, *(value[:Update1].operands + value[:_Update_3].operands))
550
+ else
551
+ value[:Update1]
552
+ end
553
+ end
554
+
555
+ # (rule _Update_4 (seq ';' Update))
556
+ production(:_Update_4) do |value|
557
+ value.last[:Update]
558
+ end
559
+
560
+ # Update1 ::= Load | Clear | Drop | Add | Move | Copy
561
+ # | Create | InsertData | DeleteData | DeleteWhere | Modify
562
+ #
563
+ # Output is SSE `(update ...)`
564
+ production(:Update1) do |value|
565
+ SPARQL::Algebra::Expression.for(:update, value)
566
+ end
567
+
568
+ # Load ::= "LOAD" "SILENT"? iri ("INTO" GraphRef)?
569
+ #
570
+ # (rule Load (seq 'LOAD' _Load_1 iri _Load_2))
571
+ # (rule _Load_1 (opt 'SILENT'))
572
+ # (rule _Load_2 (opt _Load_3))
573
+ # (rule _Load_3 (seq 'INTO' GraphRef))
574
+ start_production(:Load, as_hash: true)
575
+ production(:Load) do |value|
576
+ args = []
577
+ args << :silent if value[:_Load_1]
578
+ args << value[:iri]
579
+ args << value[:_Load_2].last[:GraphRef] if value[:_Load_2]
580
+ SPARQL::Algebra::Expression(:load, *args)
581
+ end
582
+
583
+ # Clear ::= "CLEAR" "SILENT"? GraphRefAll
584
+ start_production(:Clear, as_hash: true)
585
+ production(:Clear) do |value|
586
+ args = []
587
+ args << :silent if value[:_Clear_1]
588
+ args << (value[:GraphRefAll].is_a?(String) ? value[:GraphRefAll].downcase.to_sym : value[:GraphRefAll])
589
+ SPARQL::Algebra::Expression(:clear, *args)
590
+ end
591
+
592
+ # Drop ::= "DROP" "SILENT"? GraphRefAll
593
+ start_production(:Drop, as_hash: true)
594
+ production(:Drop) do |value|
595
+ args = []
596
+ args << :silent if value[:_Drop_1]
597
+ args << (value[:GraphRefAll].is_a?(String) ? value[:GraphRefAll].downcase.to_sym : value[:GraphRefAll])
598
+ SPARQL::Algebra::Expression(:drop, *args)
599
+ end
600
+
601
+ # Create ::= "CREATE" "SILENT"? GraphRef
602
+ start_production(:Create, as_hash: true)
603
+ production(:Create) do |value|
604
+ args = []
605
+ args << :silent if value[:_Create_1]
606
+ args << (value[:GraphRef].is_a?(String) ? value[:GraphRef].downcase.to_sym : value[:GraphRef])
607
+ SPARQL::Algebra::Expression(:create, *args)
608
+ end
609
+
610
+ # Add ::= "ADD" "SILENT"? GraphOrDefault "TO" GraphOrDefault
611
+ #
612
+ # Input is `GraphOrDefault` and optionally `:silent`.
613
+ # Output is an `Operator::Add` object.
614
+ production(:Add) do |value|
615
+ args = []
616
+ args << :silent if value[1][:_Add_1]
617
+ args << value[2][:GraphOrDefault]
618
+ args << value[4][:GraphOrDefault]
619
+ SPARQL::Algebra::Expression(:add, *args)
620
+ end
621
+
622
+ # Move ::= "MOVE" "SILENT"? GraphOrDefault "TO" GraphOrDefault
623
+ production(:Move) do |value|
624
+ args = []
625
+ args << :silent if value[1][:_Move_1]
626
+ args << value[2][:GraphOrDefault]
627
+ args << value[4][:GraphOrDefault]
628
+ SPARQL::Algebra::Expression(:move, *args)
629
+ end
630
+
631
+ # Copy ::= "COPY" "SILENT"? GraphOrDefault "TO" GraphOrDefault
632
+ production(:Copy) do |value|
633
+ args = []
634
+ args << :silent if value[1][:_Copy_1]
635
+ args << value[2][:GraphOrDefault]
636
+ args << value[4][:GraphOrDefault]
637
+ SPARQL::Algebra::Expression(:copy, *args)
638
+ end
639
+
640
+ # InsertData ::= "INSERT DATA" QuadData
641
+ #
642
+ # Freeze existing bnodes, so that if an attempt is made to re-use such a node, and error is raised
643
+ #
644
+ # Returns (insertData ...)
645
+ start_production(:InsertData, as_hash: true)
646
+ production(:InsertData) do |value|
647
+ SPARQL::Algebra::Expression(:insertData, value[:QuadData])
648
+ end
649
+
650
+ # DeleteData ::= "DELETE DATA" QuadData
651
+ # Generate BNodes instead of non-distinguished variables. BNodes are not legal, but this will generate them rather than non-distinguished variables so they can be detected.
652
+ start_production(:DeleteData, as_hash: true)
653
+ production(:DeleteData) do |value|
654
+ raise Error, "DeleteData contains BNode operands: #{value[:QuadData].to_sse}" if Array(value[:QuadData]).any?(&:node?)
655
+ SPARQL::Algebra::Expression(:deleteData, value[:QuadData])
656
+ end
657
+
658
+ # DeleteWhere ::= "DELETE WHERE" QuadPattern
659
+ # Generate BNodes instead of non-distinguished variables. BNodes are not legal, but this will generate them rather than non-distinguished variables so they can be detected.
660
+ start_production(:DeleteWhere, as_hash: true)
661
+ production(:DeleteWhere) do |value|
662
+ raise Error, "DeleteWhere contains BNode operands: #{value[:QuadPattern].to_sse}" if Array(value[:QuadPattern]).any?(&:node?)
663
+ SPARQL::Algebra::Expression(:deleteWhere, Array(value[:QuadPattern]))
664
+ end
665
+
666
+ #
667
+ # Modify::= ( 'WITH' iri )? ( DeleteClause InsertClause? | InsertClause ) UsingClause* 'WHERE' GroupGraphPattern
668
+ #
669
+ # (rule Modify (seq _Modify_1 _Modify_2 _Modify_3 'WHERE' GroupGraphPattern))
670
+ # (rule _Modify_1 (opt _Modify_4))
671
+ # (rule _Modify_4 (seq 'WITH' iri))
672
+ # (rule _Modify_2 (alt _Modify_5 InsertClause))
673
+ # (rule _Modify_5 (seq DeleteClause _Modify_6))
674
+ # (rule _Modify_6 (opt InsertClause))
675
+ # (rule _Modify_3 (star UsingClause))
676
+ #
677
+ # Returns modify operand
678
+ start_production(:Modify, as_hash: true)
679
+ production(:Modify) do |value|
680
+ query = value&.dig(:GroupGraphPattern, :query)
681
+ query = SPARQL::Algebra::Expression.for(:using, value[:_Modify_3], query) unless value[:_Modify_3].empty?
682
+ operands = [query, *Array(value[:_Modify_2])].compact
683
+ operands = [SPARQL::Algebra::Expression.for(:with, value[:_Modify_1], *operands)] if value[:_Modify_1]
684
+ SPARQL::Algebra::Expression(:modify, *operands)
685
+ end
686
+
687
+ # (rule _Modify_2 (alt _Modify_5 InsertClause))
688
+ #
689
+ # Clear cached bnodes here to be able to detect illegal attempt to re-define
690
+ #
691
+ # XXX Doe we really need to clear the cache?
692
+ start_production(:_Modify_2) {self.clear_bnode_cache}
693
+
694
+ # (rule _Modify_4 (seq 'WITH' iri))
695
+ production(:_Modify_4) do |value|
696
+ value.last[:iri]
697
+ end
698
+
699
+ # (rule _Modify_5 (seq DeleteClause _Modify_6))
700
+ start_production(:_Modify_5, as_hash: true)
701
+ production(:_Modify_5) do |value|
702
+ [value[:DeleteClause], value[:_Modify_6]]
703
+ end
704
+
705
+ # DeleteClause ::= "DELETE" QuadPattern
706
+ #
707
+ # Generate BNodes instead of non-distinguished variables. BNodes are not legal, but this will generate them rather than non-distinguished variables so they can be detected.
708
+ start_production(:DeleteClause, as_hash: true)
709
+ production(:DeleteClause) do |value|
710
+ raise Error, "DeleteClause contains BNode operands: #{Array(value[:QuadPattern]).to_sse}" if Array(value[:QuadPattern]).any?(&:node?)
711
+ SPARQL::Algebra::Expression(:delete, Array(value[:QuadPattern]))
712
+ end
713
+
714
+ # InsertClause ::= "INSERT" QuadPattern
715
+ #
716
+ # Generate BNodes instead of non-distinguished variables.
717
+ start_production(:InsertClause, as_hash: true)
718
+ production(:InsertClause) do |value|
719
+ SPARQL::Algebra::Expression(:insert, Array(value[:QuadPattern]))
720
+ end
721
+
722
+ # UsingClause ::= "USING" ( iri | "NAMED" iri)
723
+ #
724
+ # (rule UsingClause (seq 'USING' _UsingClause_1))
725
+ # (rule _UsingClause_1 (alt iri _UsingClause_2))
726
+ # (rule _UsingClause_2 (seq 'NAMED' iri))
727
+ #
728
+ start_production(:UsingClause, as_hash: true)
729
+ production(:UsingClause) do |value|
730
+ value[:_UsingClause_1]
731
+ end
732
+
733
+ # (rule _UsingClause_2 (seq 'NAMED' iri))
734
+ start_production(:_UsingClause_2, as_hash: true)
735
+ production(:_UsingClause_2) do |value|
736
+ [:named, value[:iri]]
737
+ end
738
+
739
+ # GraphOrDefault ::= "DEFAULT" | "GRAPH"? iri
740
+ #
741
+ # (rule GraphOrDefault (alt 'DEFAULT' _GraphOrDefault_1))
742
+ # (rule _GraphOrDefault_1 (seq _GraphOrDefault_2 iri))
743
+ # (rule _GraphOrDefault_2 (opt 'GRAPH'))
744
+ production(:GraphOrDefault) do |value|
745
+ value.is_a?(String) ? value.downcase.to_sym : value
746
+ end
747
+ start_production(:_GraphOrDefault_1, as_hash: true)
748
+ production(:_GraphOrDefault_1) {|value| value[:iri]}
749
+
750
+ # GraphRef ::= "GRAPH" iri
751
+ production(:GraphRef) do |value|
752
+ value.last[:iri]
753
+ end
754
+
755
+ # QuadPattern::= '{' Quads '}'
756
+ # Returns array of patterns
757
+ start_production(:QuadPattern, as_hash: true) {self.gen_bnodes}
758
+ production(:QuadPattern) do |value|
759
+ self.gen_bnodes(false)
760
+ value[:Quads]
761
+ end
762
+
763
+ # QuadData ::= "{" Quads "}"
764
+ #
765
+ # QuadData is like QuadPattern, except without BNodes
766
+ # Generate BNodes instead of non-distinguished variables
767
+ #
768
+ # Returns array of patterns
769
+ start_production(:QuadData, as_hash: true) do |data|
770
+ # Freeze bnodes if called from INSERT DATA
771
+ self.freeze_bnodes if data[:_rept_data].first.key?(:"INSERT DATA")
772
+ self.gen_bnodes
773
+ end
774
+ production(:QuadData) do |value|
775
+ # Transform using statements instead of patterns, and verify there are no variables
776
+ raise Error, "QuadData contains variable operands: #{Array(value[:Quads]).to_sse}" if Array(value[:Quads]).any?(&:variable?)
777
+ self.gen_bnodes(false)
778
+ value[:Quads]
779
+ end
780
+
781
+ # Quads ::= TriplesTemplate? ( QuadsNotTriples '.'? TriplesTemplate? )*
782
+ #
783
+ # (rule Quads (seq _Quads_1 _Quads_2))
784
+ # (rule _Quads_1 (opt TriplesTemplate))
785
+ # (rule _Quads_2 (star _Quads_3))
786
+ # (rule _Quads_3 (seq QuadsNotTriples _Quads_4 _Quads_5))
787
+ # (rule _Quads_4 (opt '.'))
788
+ # (rule _Quads_5 (opt TriplesTemplate))
789
+ #
790
+ # Returns an array of patterns
791
+ start_production(:Quads, as_hash: true)
792
+ production(:Quads) do |value|
793
+ Array(value[:_Quads_1]) + value[:_Quads_2].flatten
794
+ end
795
+
796
+ # (rule _Quads_3 (seq QuadsNotTriples _Quads_4 _Quads_5))
797
+ start_production(:_Quads_3, as_hash: true)
798
+ production(:_Quads_3) do |value|
799
+ [value[:QuadsNotTriples]] + Array(value[:_Quads_5])
800
+ end
801
+
802
+ # QuadsNotTriples ::= "GRAPH" VarOrIri "{" TriplesTemplate? "}"
803
+ #
804
+ # (rule QuadsNotTriples (seq 'GRAPH' VarOrIri '{' _QuadsNotTriples_1 '}'))
805
+ # (rule _QuadsNotTriples_1 (opt TriplesTemplate))
806
+ #
807
+ # Result is Graph operator
808
+ start_production(:QuadsNotTriples, as_hash: true)
809
+ production(:QuadsNotTriples) do |value|
810
+ SPARQL::Algebra::Expression.for(:graph, value[:VarOrIri], Array(value[:_QuadsNotTriples_1]))
811
+ end
812
+
813
+ # TriplesTemplate ::= TriplesSameSubject ("." TriplesTemplate? )?
814
+ #
815
+ # (rule TriplesTemplate (seq TriplesSameSubject _TriplesTemplate_1))
816
+ # (rule _TriplesTemplate_1 (opt _TriplesTemplate_2))
817
+ # (rule _TriplesTemplate_2 (seq '.' _TriplesTemplate_3))
818
+ # (rule _TriplesTemplate_3 (opt TriplesTemplate))
819
+ #
820
+ # Returnes patterns
821
+ start_production(:TriplesTemplate, as_hash: true)
822
+ production(:TriplesTemplate) do |value|
823
+ value[:TriplesSameSubject] + Array(value[:_TriplesTemplate_1])
824
+ end
825
+
826
+ # (rule _TriplesTemplate_2 (seq '.' _TriplesTemplate_3))
827
+ production(:_TriplesTemplate_2) do |value|
828
+ value.last[:_TriplesTemplate_3]
829
+ end
830
+
831
+ # GroupGraphPattern ::= '{' ( SubSelect | GroupGraphPatternSub ) '}'
832
+ start_production(:GroupGraphPattern, as_hash: true)
833
+ production(:GroupGraphPattern) do |value|
834
+ {query: value&.dig(:_GroupGraphPattern_1, :query)}
835
+ end
836
+
837
+ # GroupGraphPatternSub ::= TriplesBlock? (GraphPatternNotTriples "."? TriplesBlock? )*
838
+ #
839
+ # (rule GroupGraphPatternSub (seq _GroupGraphPatternSub_1 _GroupGraphPatternSub_2))
840
+ # (rule _GroupGraphPatternSub_1 (opt TriplesBlock))
841
+ # (rule _GroupGraphPatternSub_2 (star _GroupGraphPatternSub_3))
842
+ # (rule _GroupGraphPatternSub_3
843
+ # (seq GraphPatternNotTriples _GroupGraphPatternSub_4 _GroupGraphPatternSub_5))
844
+ # (rule _GroupGraphPatternSub_4 (opt '.'))
845
+ # (rule _GroupGraphPatternSub_5 (opt TriplesBlock))
846
+ start_production(:GroupGraphPatternSub, as_hash: true)
847
+ production(:GroupGraphPatternSub) do |value|
848
+ query = value[:_GroupGraphPatternSub_1] || SPARQL::Algebra::Operator::BGP.new
849
+ extensions = []
850
+ filters = []
851
+
852
+ value[:_GroupGraphPatternSub_2].each do |ggps2|
853
+ filters << ggps2[:filter] if ggps2[:filter]
854
+
855
+ bgp = ggps2[:query]
856
+ query = if bgp && query.mergable?(bgp) && false # XXX No agressive merging
857
+ query.merge(bgp)
858
+ elsif query.empty? && bgp
859
+ bgp
860
+ elsif !bgp || bgp.empty?
861
+ query
862
+ else
863
+ SPARQL::Algebra::Operator::Join.new(query, bgp)
864
+ end
865
+
866
+ # Extensions
867
+ if ggps2[:extend]
868
+ # Extensions will be an array of pairs of variable and expression
869
+ error(nil,
870
+ "Internal error on extensions form",
871
+ production: :GroupGraphPatternSub,
872
+ fatal: true) unless
873
+ ggps2[:extend].is_a?(Array) && ggps2[:extend].all? {|e| e.is_a?(Array)}
874
+
875
+ # The variable assigned in a BIND clause must not be already in-use within the immediately preceding TriplesBlock within a GroupGraphPattern.
876
+ # None of the variables on the lhs of data[:extend] may be used in lhs
877
+ ggps2[:extend].each do |(v, _)|
878
+ error(nil, "BIND Variable #{v} used in pattern", production: :GraphPatternNotTriples) if query.vars.map(&:to_sym).include?(v.to_sym)
879
+ end
880
+ query = if query.is_a?(SPARQL::Algebra::Operator::Extend)
881
+ # Coalesce extensions
882
+ lhs = query.dup
883
+ lhs.operands.first.concat(ggps2[:extend])
884
+ lhs
885
+ else
886
+ SPARQL::Algebra::Expression[:extend, ggps2[:extend], query] unless ggps2[:extend].empty?
887
+ end
888
+ end
889
+
890
+ # _GroupGraphPatternSub_3 can return patterns from TriplesBlock?
891
+ if bgp = ggps2[:extra]
892
+ query = if query.mergable?(bgp) && false # XXX No agressive merging
893
+ query.merge(bgp)
894
+ elsif query.empty?
895
+ bgp
896
+ elsif bgp.empty?
897
+ query
898
+ elsif bgp.is_a?(SPARQL::Algebra::Operator::Path)
899
+ SPARQL::Algebra::Operator::Sequence.new(query, bgp)
900
+ else
901
+ SPARQL::Algebra::Operator::Join.new(query, bgp)
902
+ end
903
+ end
904
+
905
+ query = if ggps2[:leftjoin]
906
+ SPARQL::Algebra::Expression.for(:leftjoin, query, *ggps2[:leftjoin])
907
+ elsif ggps2[:minus]
908
+ SPARQL::Algebra::Expression.for(:minus, query, ggps2[:minus])
909
+ else
910
+ query
911
+ end
912
+ end
913
+
914
+ # Filters
915
+ unless filters.empty?
916
+ expr = filters.length > 1 ? SPARQL::Algebra::Operator::Exprlist.new(*filters) : filters.first
917
+ query = SPARQL::Algebra::Operator::Filter.new(expr, query)
918
+ end
919
+
920
+ {query: query}
921
+ end
922
+
923
+ # (rule _GroupGraphPatternSub_3
924
+ # (seq GraphPatternNotTriples _GroupGraphPatternSub_4 _GroupGraphPatternSub_5))
925
+ start_production(:_GroupGraphPatternSub_3, as_hash: true)
926
+ production(:_GroupGraphPatternSub_3) do |value|
927
+ {
928
+ extend: value&.dig(:GraphPatternNotTriples, :extend),
929
+ extra: value[:_GroupGraphPatternSub_5],
930
+ filter: value&.dig(:GraphPatternNotTriples, :filter),
931
+ leftjoin: value&.dig(:GraphPatternNotTriples, :leftjoin),
932
+ minus: value&.dig(:GraphPatternNotTriples, :minus),
933
+ query: value&.dig(:GraphPatternNotTriples, :query),
934
+ }
935
+ end
936
+
937
+ # TriplesBlock ::= TriplesSameSubjectPath
938
+ # ( '.' TriplesBlock? )?
939
+ #
940
+ # (rule TriplesBlock (seq TriplesSameSubjectPath _TriplesBlock_1))
941
+ # (rule _TriplesBlock_1 (opt _TriplesBlock_2))
942
+ # (rule _TriplesBlock_2 (seq '.' _TriplesBlock_3))
943
+ # (rule _TriplesBlock_3 (opt TriplesBlock))
944
+ start_production(:TriplesBlock, as_hash: true)
945
+ production(:TriplesBlock) do |value|
946
+ tb1 = value[:_TriplesBlock_1]
947
+ sequence = Array(value[:TriplesSameSubjectPath])
948
+
949
+ # Append triples from ('.' TriplesBlock? )?
950
+ if tb1.is_a?(SPARQL::Algebra::Operator::Sequence)
951
+ tb1.operands.each do |op|
952
+ sequence += op.respond_to?(:patterns) ? op.patterns : [op]
953
+ end
954
+ elsif tb1.respond_to?(:patterns)
955
+ sequence += tb1.patterns
956
+ elsif tb1
957
+ sequence << tb1
958
+ end
959
+
960
+ # Merge runs of patterns into BGPs
961
+ patterns = []
962
+ new_seq = []
963
+ sequence.each do |element|
964
+ case element
965
+ when RDF::Query::Pattern
966
+ patterns << element
967
+ when RDF::Queryable
968
+ patterns += element.patterns
969
+ else
970
+ new_seq << SPARQL::Algebra::Operator::BGP.new(*patterns) unless patterns.empty?
971
+ patterns = []
972
+ new_seq << element
973
+ end
974
+ end
975
+ new_seq << SPARQL::Algebra::Operator::BGP.new(*patterns) unless patterns.empty?
976
+
977
+ # Optionally create a sequence, if there are enough gathered.
978
+ # FIXME: Join?
979
+ if new_seq.length > 1
980
+ if new_seq.any? {|e| e.is_a?(SPARQL::Algebra::Operator::Path)}
981
+ SPARQL::Algebra::Expression.for(:sequence, *new_seq)
982
+ else
983
+ SPARQL::Algebra::Expression.for(:join, *new_seq)
984
+ end
985
+ else
986
+ new_seq.first
987
+ end
988
+ end
989
+
990
+ # (rule _TriplesBlock_2 (seq '.' _TriplesBlock_3))
991
+ start_production(:_TriplesBlock_2, as_hash: true)
992
+ production(:_TriplesBlock_2) do |value|
993
+ value[:_TriplesBlock_3]
994
+ end
995
+
996
+ # ReifiedTripleBlock ::= ReifiedTriple PropertyList
997
+ start_production(:ReifiedTripleBlock, as_hash: true)
998
+ production(:ReifiedTripleBlock) do |value|
999
+ {ReifiedTripleBlock: value[:ReifiedTriple][:pattern] + Array(value[:PropertyList])}
1000
+ end
1001
+
1002
+ # ReifiedTripleBlockPath ::= ReifiedTriple PropertyListPath
1003
+ #
1004
+ # Returns `{ReifiedTripleBlockPath: patterns}`
1005
+ start_production(:ReifiedTripleBlockPath, as_hash: true)
1006
+ production(:ReifiedTripleBlockPath) do |value|
1007
+ {ReifiedTripleBlockPath: value[:ReifiedTriple][:pattern] + Array(value[:PropertyListPath])}
1008
+ end
1009
+
1010
+ # OptionalGraphPattern ::= 'OPTIONAL' GroupGraphPattern
1011
+ #
1012
+ # FIXME: This should not extract a filter if there is more than one level of curly braces.
1013
+ start_production(:OptionalGraphPattern, as_hash: true)
1014
+ production(:OptionalGraphPattern) do |value|
1015
+ query = value&.dig(:GroupGraphPattern, :query) || SPARQL::Algebra::Operator::BGP.new
1016
+ if query.is_a?(SPARQL::Algebra::Operator::Filter)
1017
+ # Change to expression on left-join with query element
1018
+ expr, query = query.operands
1019
+ {leftjoin: [query, expr]}
1020
+ elsif !query.empty?
1021
+ {leftjoin: [query]}
1022
+ end
1023
+ end
1024
+
1025
+ # GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern
1026
+ start_production(:GraphGraphPattern, as_hash: true)
1027
+ production(:GraphGraphPattern) do |value|
1028
+ name = value[:VarOrIri]
1029
+ bgp = value&.dig(:GroupGraphPattern, :query) || SPARQL::Algebra::Operator::BGP.new
1030
+ {
1031
+ query: (name ? SPARQL::Algebra::Expression.for(:graph, name, bgp) : bgp)
1032
+ }
1033
+ end
1034
+
1035
+ # ServiceGraphPattern ::= 'SERVICE' 'SILENT'? VarOrIri GroupGraphPattern
1036
+ start_production(:ServiceGraphPattern, as_hash: true)
1037
+ production(:ServiceGraphPattern) do |value|
1038
+ query = value&.dig(:GroupGraphPattern, :query) || SPARQL::Algebra::Operator::BGP.new
1039
+ args = []
1040
+ args << :silent if value[:_ServiceGraphPattern_1]
1041
+ args << value[:VarOrIri]
1042
+ args << query
1043
+ service = SPARQL::Algebra::Expression.for(:service, *args)
1044
+ {query: service}
1045
+ end
1046
+
1047
+ # Bind ::= 'BIND' '(' Expression 'AS' Var ')'
1048
+ start_production(:Bind, as_hash: true)
1049
+ production(:Bind) do |value|
1050
+ {extend: [[value[:Var], value[:Expression]]]}
1051
+ end
1052
+
1053
+ # InlineData ::= 'VALUES' DataBlock
1054
+ start_production(:InlineData, as_hash: true)
1055
+ production(:InlineData) do |value|
1056
+ debug("InlineData") {value[:DataBlock].inspect}
1057
+ args = [Array(value[:DataBlock][:Var]).unshift(:vars)] + value[:DataBlock][:row]
1058
+ table = SPARQL::Algebra::Expression.for(:table, *args)
1059
+ {query: table}
1060
+ end
1061
+
1062
+ # InlineDataOneVar ::= Var '{' DataBlockValue* '}'
1063
+ start_production(:InlineDataOneVar, as_hash: true)
1064
+ production(:InlineDataOneVar) do |value|
1065
+ {
1066
+ Var: value[:Var],
1067
+ row: value[:_InlineDataOneVar_1].map {|dbv| [:row, [value[:Var], dbv]]}
1068
+ }
1069
+ end
1070
+
1071
+ # InlineDataFull ::= ( NIL | '(' Var* ')' )
1072
+ # '{' ( '(' DataBlockValue* ')' | NIL )* '}'
1073
+ #
1074
+ # (rule InlineDataFull (seq _InlineDataFull_1 '{' _InlineDataFull_2 '}'))
1075
+ # (rule _InlineDataFull_1 (alt NIL _InlineDataFull_3))
1076
+ # (rule _InlineDataFull_3 (seq '(' _InlineDataFull_4 ')'))
1077
+ # (rule _InlineDataFull_4 (star Var))
1078
+ # (rule _InlineDataFull_2 (star _InlineDataFull_5))
1079
+ # (rule _InlineDataFull_5 (alt _InlineDataFull_6 NIL))
1080
+ # (rule _InlineDataFull_6 (seq '(' _InlineDataFull_7 ')'))
1081
+ # (rule _InlineDataFull_7 (star DataBlockValue))
1082
+ #
1083
+ start_production(:InlineDataFull, as_hash: true)
1084
+ production(:InlineDataFull) do |value|
1085
+ vars = value[:_InlineDataFull_1]
1086
+ vars = [] if vars == RDF.nil
1087
+
1088
+ rows = value[:_InlineDataFull_2].map do |ds|
1089
+ # XXX what if ds == RDF.nil
1090
+ if ds.length < vars.length
1091
+ raise Error, "Too few values in a VALUE clause compared to the number of variables"
1092
+ elsif ds.length > vars.length
1093
+ raise Error, "Too many values in a VALUE clause compared to the number of variables"
1094
+ end
1095
+ r = [:row]
1096
+ ds.each_with_index do |d, i|
1097
+ r << [vars[i], d] if d
1098
+ end
1099
+ r unless r.empty?
1100
+ end.compact
1101
+
1102
+ {
1103
+ Var: vars,
1104
+ row: rows
1105
+ }
1106
+ end
1107
+
1108
+ # (rule _InlineDataFull_3 (seq '(' _InlineDataFull_4 ')'))
1109
+ start_production(:_InlineDataFull_3, as_hash: true)
1110
+ production(:_InlineDataFull_3) do |value|
1111
+ value[:_InlineDataFull_4]
1112
+ end
1113
+
1114
+ # (rule _InlineDataFull_6 (seq '(' _InlineDataFull_7 ')'))
1115
+ start_production(:_InlineDataFull_6, as_hash: true)
1116
+ production(:_InlineDataFull_6) do |value|
1117
+ value[:_InlineDataFull_7]
1118
+ end
1119
+
1120
+ # Reifier ::= '~' VarOrReifierId?
1121
+ #
1122
+ # Beginning the reifier production, the curReifier is taken from the reifier term constructor. Then yield the the RDF triple curReifier rdf:reifies curTripleTerm.
1123
+ #
1124
+ # Returns emitted pattern
1125
+ start_production(:Reifier, as_hash: true)
1126
+ production(:Reifier) do |value|
1127
+ rid = prod_data[:curReifier] = value[:_Reifier_1] || bnode
1128
+ RDF::Query::Pattern.new(rid, RDF.reifies, prod_data[:TripleTerm]) if prod_data[:TripleTerm]
1129
+ end
1130
+
1131
+ # MinusGraphPattern ::= 'MINUS' GroupGraphPattern
1132
+ start_production(:MinusGraphPattern, as_hash: true)
1133
+ production(:MinusGraphPattern) do |value|
1134
+ query = value&.dig(:GroupGraphPattern, :query) || SPARQL::Algebra::Operator::BGP.new
1135
+ {minus: query}
1136
+ end
1137
+
1138
+ # GroupOrUnionGraphPattern ::= GroupGraphPattern
1139
+ # ( 'UNION' GroupGraphPattern )*
1140
+ start_production(:GroupOrUnionGraphPattern, as_hash: true)
1141
+ production(:GroupOrUnionGraphPattern) do |value|
1142
+ lhs = value&.dig(:GroupGraphPattern, :query)
1143
+ query = value[:_GroupOrUnionGraphPattern_1].reduce(lhs) do |memo, q|
1144
+ SPARQL::Algebra::Expression.for(:union, memo, q)
1145
+ end
1146
+
1147
+ {query: query}
1148
+ end
1149
+
1150
+ # (rule _GroupOrUnionGraphPattern_2 (seq 'UNION' GroupGraphPattern))
1151
+ start_production(:_GroupOrUnionGraphPattern_2, as_hash: true)
1152
+ production(:_GroupOrUnionGraphPattern_2) do |value|
1153
+ value&.dig(:GroupGraphPattern, :query)
1154
+ end
1155
+
1156
+ # Filter ::= 'FILTER' Constraint
1157
+ start_production(:Filter, as_hash: true)
1158
+ production(:Filter) do |value|
1159
+ {filter: value[:Constraint]}
1160
+ end
1161
+
1162
+ # FunctionCall ::= iri ArgList
1163
+ start_production(:FunctionCall, as_hash: true)
1164
+ production(:FunctionCall) do |value|
1165
+ SPARQL::Algebra::Operator::FunctionCall.new(value[:iri], *value[:ArgList])
1166
+ end
1167
+
1168
+ # ArgList ::= NIL | '(' 'DISTINCT'? Expression ( ',' Expression )* ')'
1169
+ #
1170
+ # (rule ArgList (alt NIL _ArgList_1))
1171
+ # (rule _ArgList_1 (seq '(' _ArgList_2 Expression _ArgList_3 ')'))
1172
+ # (rule _ArgList_2 (opt 'DISTINCT'))
1173
+ # (rule _ArgList_3 (star _ArgList_4))
1174
+ # (rule _ArgList_4 (seq ',' Expression))
1175
+ #
1176
+ # XXX handle DISTINCT?
1177
+ production(:ArgList) do |value|
1178
+ Array(value)
1179
+ end
1180
+
1181
+ start_production(:_ArgList_1, as_hash: true)
1182
+ production(:_ArgList_1) do |value|
1183
+ value[:_ArgList_3].unshift(value[:Expression])
1184
+ end
1185
+
1186
+ start_production(:_ArgList_4, as_hash: true)
1187
+ production(:_ArgList_4) do |value|
1188
+ value[:Expression]
1189
+ end
1190
+
1191
+ # ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')'
1192
+ #
1193
+ # (rule ExpressionList (alt NIL _ExpressionList_1))
1194
+ production(:ExpressionList) do |value|
1195
+ value.is_a?(RDF::Term) ? [] : value.flatten
1196
+ end
1197
+
1198
+ # (rule _ExpressionList_1 (seq '(' Expression _ExpressionList_2 ')'))
1199
+ production(:_ExpressionList_1) do |value|
1200
+ [value[1][:Expression], value[2][:_ExpressionList_2]].compact
1201
+ end
1202
+
1203
+ # (rule _ExpressionList_2 (star _ExpressionList_3))
1204
+ # (rule _ExpressionList_3 (seq ',' Expression))
1205
+ production(:_ExpressionList_2) do |value|
1206
+ value.map {|el3| el3.last[:Expression]}
1207
+ end
1208
+
1209
+ # ConstructTemplate ::= '{' ConstructTriples? '}'
1210
+ start_production(:ConstructTemplate, as_hash: true)
1211
+ production(:ConstructTemplate) do |value|
1212
+ # Generate BNodes instead of non-distinguished variables
1213
+ self.gen_bnodes(false)
1214
+ value[:_ConstructTemplate_1]
1215
+ end
1216
+
1217
+ # ConstructTriples ::= TriplesSameSubject ( '.' ConstructTriples? )?
1218
+ # Returns patterns
1219
+ start_production(:ConstructTriples, as_hash: true) do
1220
+ # Generate BNodes instead of non-distinguished variables
1221
+ self.gen_bnodes
1222
+ end
1223
+ production(:ConstructTriples) do |value|
1224
+ # Generate BNodes instead of non-distinguished variables
1225
+ value[:TriplesSameSubject] + Array(value[:_ConstructTriples_1])
1226
+ end
1227
+
1228
+ # (rule _ConstructTriples_2 (seq '.' _ConstructTriples_3))
1229
+ start_production(:_ConstructTriples_2, as_hash: true)
1230
+ production(:_ConstructTriples_2) do |value|
1231
+ value[:_ConstructTriples_3]
1232
+ end
1233
+
1234
+ # TriplesSameSubject ::= VarOrTerm PropertyListNotEmpty
1235
+ # | TriplesNode PropertyList | ReifiedTripleBlock
1236
+ #
1237
+ # (rule TriplesSameSubject
1238
+ # (alt _TriplesSameSubject_1 _TriplesSameSubject_2 ReifiedTripleBlock))
1239
+ # (rule _TriplesSameSubject_1 (seq VarOrTerm PropertyListNotEmpty))
1240
+ # (rule _TriplesSameSubject_2 (seq TriplesNode PropertyList))
1241
+ #
1242
+ # Returns patterns
1243
+ production(:TriplesSameSubject) do |value|
1244
+ pattern = if value[:VarOrTerm]
1245
+ value[:PropertyListNotEmpty]
1246
+ elsif value[:TriplesNode]
1247
+ value[:TriplesNode][:pattern] + Array(value[:PropertyList])
1248
+ elsif value[:ReifiedTripleBlock]
1249
+ value[:ReifiedTripleBlock]
1250
+ else
1251
+ []
1252
+ end
1253
+ pattern
1254
+ end
1255
+
1256
+ # (rule _TriplesSameSubject_1 (seq VarOrTerm PropertyListNotEmpty))
1257
+ start_production(:_TriplesSameSubject_1, as_hash: true)
1258
+
1259
+ # (rule _TriplesSameSubject_2 (seq TriplesNode PropertyList))
1260
+ start_production(:_TriplesSameSubject_2, as_hash: true)
1261
+
1262
+ # PropertyList ::= PropertyListNotEmpty?
1263
+
1264
+ # PropertyListNotEmpty ::= Verb ObjectList
1265
+ # ( ';' ( Verb ObjectList )? )*
1266
+ #
1267
+ # (rule PropertyListNotEmpty (seq Verb ObjectList _PropertyListNotEmpty_1))
1268
+ # (rule _PropertyListNotEmpty_1 (star _PropertyListNotEmpty_2))
1269
+ # (rule _PropertyListNotEmpty_2 (seq ';' _PropertyListNotEmpty_3))
1270
+ # (rule _PropertyListNotEmpty_3 (opt _PropertyListNotEmpty_4))
1271
+ # (rule _PropertyListNotEmpty_4 (seq Verb ObjectList))
1272
+ #
1273
+ # Returns patterns
1274
+ start_production(:PropertyListNotEmpty, as_hash: true) do |data|
1275
+ # If we're in an AnnotationPathBlock, use reification information
1276
+ if anno_data = prod_data[:AnnotationData]
1277
+ # Allocate a reifier ID, if necessary and use as subject
1278
+ prod_data[:Subject] = anno_data[:curReifier] ||= bnode
1279
+ end
1280
+
1281
+ # If options has a `:_rept_data` entry, use it to get the subject
1282
+ subject = prod_data[:Subject] || prod_data[:TriplesNode] || data[:_rept_data].last[:VarOrTerm]
1283
+ error(nil, "Expected VarOrTerm or TriplesNode or GraphNode", production: :PropertyListNotEmpty) if !subject
1284
+ data[:Subject] = subject
1285
+ end
1286
+ production(:PropertyListNotEmpty) do |value|
1287
+ patterns = Array(value[:ObjectList][:pattern])
1288
+ value[:_PropertyListNotEmpty_1].each do |plne|
1289
+ patterns += plne[:pattern]
1290
+ end
1291
+ patterns
1292
+ end
1293
+
1294
+ # (rule _PropertyListNotEmpty_2 (seq ';' _PropertyListNotEmpty_3))
1295
+ start_production(:_PropertyListNotEmpty_2, as_hash: true) do |data|
1296
+ data[:Subject] = prod_data[:Subject]
1297
+ end
1298
+ production(:_PropertyListNotEmpty_2) do |value|
1299
+ value[:_PropertyListNotEmpty_3]
1300
+ end
1301
+
1302
+ # (rule _PropertyListNotEmpty_4 (seq Verb ObjectList))
1303
+ start_production(:_PropertyListNotEmpty_4, as_hash: true) do |data|
1304
+ data[:Subject] = prod_data[:Subject]
1305
+ end
1306
+ production(:_PropertyListNotEmpty_4) do |value|
1307
+ value[:ObjectList]
1308
+ end
1309
+
1310
+ # Verb ::= VarOrIri | 'a'
1311
+ #
1312
+ # Output to input is `:Verb`.
1313
+ start_production(:Verb, as_hash: true, insensitive_strings: false)
1314
+ production(:Verb) do |value|
1315
+ value == 'a' ? RDF.type.dup.tap {|a| a.lexical = 'a'} : value
1316
+ end
1317
+
1318
+ # ObjectList ::= Object ( ',' Object )*
1319
+ #
1320
+ # (rule ObjectList (seq Object _ObjectList_1))
1321
+ # (rule _ObjectList_1 (star _ObjectList_2))
1322
+ # (rule _ObjectList_2 (seq ',' Object))
1323
+ #
1324
+ # Returns objects and patterns
1325
+ start_production(:ObjectList, as_hash: true) do |data|
1326
+ # Called after Verb. The prod_data stack should have Subject and Verb elements
1327
+ data[:Subject] = prod_data[:Subject]
1328
+ data[:Verb] = data[:_rept_data].last[:Verb]
1329
+ error(nil, "Expected Subject", production: :ObjectList) if !data[:Subject]
1330
+ error(nil, "Expected Verb", production: :ObjectList) if !(data[:Verb])
1331
+ end
1332
+ production(:ObjectList) do |value|
1333
+ objects = Array(value[:Object][:object])
1334
+ patterns = Array(value[:Object][:pattern])
1335
+
1336
+ value[:_ObjectList_1].each do |ob|
1337
+ objects << ob[:object]
1338
+ patterns += Array(ob[:pattern])
1339
+ end
1340
+
1341
+ {
1342
+ object: objects,
1343
+ pattern: patterns
1344
+ }
1345
+ end
1346
+
1347
+ # (rule _ObjectList_2 (seq ',' Object))
1348
+ start_production(:_ObjectList_2, as_hash: true) do |data|
1349
+ data[:Subject] = prod_data[:Subject]
1350
+ data[:Verb] = prod_data[:Verb]
1351
+ end
1352
+ production(:_ObjectList_2) do |value|
1353
+ value[:Object]
1354
+ end
1355
+
1356
+ # Object ::= GraphNode Annotation
1357
+ #
1358
+ # Sets `:Subject` and `:Verb` in data from input.
1359
+ start_production(:Object, as_hash: true) do |data|
1360
+ data[:Subject] = prod_data[:Subject]
1361
+ data[:Verb] = prod_data[:Verb]
1362
+ end
1363
+ production(:Object) do |value, data|
1364
+ subject = data[:Subject]
1365
+ verb = data[:Verb]
1366
+ object = value[:GraphNode][:object]
1367
+ patterns = [RDF::Query::Pattern.new(subject, verb, object)]
1368
+ {
1369
+ object: object,
1370
+ pattern: patterns + value[:GraphNode][:pattern] + value[:Annotation]
1371
+ }
1372
+ end
1373
+
1374
+
1375
+ # TriplesSameSubjectPath ::= VarOrTerm PropertyListPathNotEmpty
1376
+ # | TriplesNodePath PropertyListPath
1377
+ # | ReifiedTripleBlockPath
1378
+ #
1379
+ # (rule TriplesSameSubjectPath
1380
+ # (alt _TriplesSameSubjectPath_1 _TriplesSameSubjectPath_2 ReifiedTripleBlockPath))
1381
+ #
1382
+ # Returns patterns
1383
+ production(:TriplesSameSubjectPath) do |value|
1384
+ pattern = if value[:VarOrTerm]
1385
+ value[:PropertyListPathNotEmpty]
1386
+ elsif value[:TriplesNodePath]
1387
+ value[:TriplesNodePath][:pattern] + Array(value[:PropertyListPath])
1388
+ elsif value[:ReifiedTripleBlockPath]
1389
+ value[:ReifiedTripleBlockPath]
1390
+ else
1391
+ []
1392
+ end
1393
+ pattern
1394
+ end
1395
+
1396
+ # (rule _TriplesSameSubjectPath_1 (seq VarOrTerm PropertyListPathNotEmpty))
1397
+ start_production(:_TriplesSameSubjectPath_1, as_hash: true)
1398
+
1399
+ # (rule _TriplesSameSubjectPath_2 (seq TriplesNodePath PropertyListPath))
1400
+ start_production(:_TriplesSameSubjectPath_2, as_hash: true)
1401
+
1402
+ # PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath
1403
+ # ( ';' ( ( VerbPath | VerbSimple )
1404
+ # ObjectListPath )? )*
1405
+ #
1406
+ # (rule PropertyListPathNotEmpty
1407
+ # (seq _PropertyListPathNotEmpty_1 ObjectListPath _PropertyListPathNotEmpty_2))
1408
+ #
1409
+ # Sets `:Subject` in data from either `:VarOrTerm`,
1410
+ # `:TriplesNode`, or `:GraphNode` in input with error checking.
1411
+ #
1412
+ # Returns patterns
1413
+ start_production(:PropertyListPathNotEmpty, as_hash: true) do |data|
1414
+ # If we're in an AnnotationPathBlock, use reification information
1415
+ if anno_data = prod_data[:AnnotationData]
1416
+ # Allocate a reifier ID, if necessary and use as subject
1417
+ prod_data[:Subject] = anno_data[:curReifier] ||= bnode
1418
+ end
1419
+
1420
+ # If options has a `:_rept_data` entry, use it to get the subject
1421
+ subject = prod_data[:Subject] ||
1422
+ prod_data[:TriplesNode] ||
1423
+ data[:_rept_data].last[:VarOrTerm]
1424
+ error(nil, "Expected Subject, got nothing", production: :PropertyListPathNotEmpty) if !subject
1425
+ data[:Subject] = subject
1426
+ end
1427
+ production(:PropertyListPathNotEmpty) do |value|
1428
+ patterns = Array(value[:ObjectListPath][:pattern])
1429
+ value[:_PropertyListPathNotEmpty_2].each do |plpne|
1430
+ patterns += plpne[:pattern]
1431
+ end
1432
+ patterns
1433
+ end
1434
+
1435
+ # (rule _PropertyListPathNotEmpty_1 (alt VerbPath VerbSimple))
1436
+
1437
+ # (rule _PropertyListPathNotEmpty_2 (star _PropertyListPathNotEmpty_3))
1438
+ start_production(:_PropertyListPathNotEmpty_2) do |data|
1439
+ data[:Subject] = prod_data[:Subject]
1440
+ end
1441
+ production(:_PropertyListPathNotEmpty_2) do |value|
1442
+ value.flatten
1443
+ end
1444
+
1445
+ # (rule _PropertyListPathNotEmpty_3 (seq ';' _PropertyListPathNotEmpty_4))
1446
+ start_production(:_PropertyListPathNotEmpty_3, as_hash: true) do |data|
1447
+ data[:Subject] = prod_data[:Subject]
1448
+ end
1449
+ production(:_PropertyListPathNotEmpty_3) do |value|
1450
+ value[:_PropertyListPathNotEmpty_4]
1451
+ end
1452
+
1453
+ # (rule _PropertyListPathNotEmpty_4 (opt _PropertyListPathNotEmpty_5))
1454
+ start_production(:_PropertyListPathNotEmpty_4) do |data|
1455
+ data[:Subject] = prod_data[:Subject]
1456
+ end
1457
+
1458
+ # (rule _PropertyListPathNotEmpty_5 (seq _PropertyListPathNotEmpty_6 ObjectListPath))
1459
+ start_production(:_PropertyListPathNotEmpty_5, as_hash: true) do |data|
1460
+ data[:Subject] = prod_data[:Subject]
1461
+ end
1462
+ production(:_PropertyListPathNotEmpty_5) do |value|
1463
+ value[:ObjectListPath]
1464
+ end
1465
+
1466
+ # VerbPath ::= Path
1467
+ start_production(:VerbPath, as_hash: true)
1468
+ production(:VerbPath) do |value|
1469
+ value[:Path]
1470
+ end
1471
+
1472
+ # VerbSimple ::= Var
1473
+ production(:VerbSimple) do |value|
1474
+ value.first[:Var]
1475
+ end
1476
+
1477
+ # ObjectListPath ::= ObjectPath ("," ObjectPath)*
1478
+ #
1479
+ # Addes `:Subject` from input to data with error checking.
1480
+ # Also adds either `:Verb` or `:VerbPath`
1481
+ #
1482
+ # Returns objects and patterns
1483
+ start_production(:ObjectListPath, as_hash: true) do |data|
1484
+ # Called after Verb. The prod_data stack should have Subject and Verb elements
1485
+ data[:Subject] = prod_data[:Subject]
1486
+ data[:Verb] = data[:_rept_data].last[:_PropertyListPathNotEmpty_1] ||
1487
+ data[:_rept_data].last[:_PropertyListPathNotEmpty_6]
1488
+ error(nil, "Expected Subject", production: :ObjectListPath) if !data[:Subject]
1489
+ error(nil, "Expected Verb", production: :ObjectListPath) if !(data[:Verb])
1490
+ end
1491
+ production(:ObjectListPath) do |value|
1492
+ objects = Array(value[:ObjectPath][:object])
1493
+ patterns = Array(value[:ObjectPath][:pattern])
1494
+ value[:_ObjectListPath_1].each do |olp|
1495
+ objects << olp[:object]
1496
+ patterns += olp[:pattern]
1497
+ end
1498
+ {
1499
+ object: objects,
1500
+ pattern: patterns
1501
+ }
1502
+ end
1503
+
1504
+ # (rule _ObjectListPath_1 (star _ObjectListPath_2))
1505
+ start_production(:_ObjectListPath_1, as_hash: true) do |data|
1506
+ data[:Subject] = prod_data[:Subject]
1507
+ data[:Verb] = prod_data[:Verb]
1508
+ end
1509
+
1510
+ # (rule _ObjectListPath_2 (seq ',' ObjectPath))
1511
+ start_production(:_ObjectListPath_2, as_hash: true) do |data|
1512
+ data[:Subject] = prod_data[:Subject]
1513
+ data[:Verb] = prod_data[:Verb]
1514
+ end
1515
+ production(:_ObjectListPath_2) do |value|
1516
+ value[:ObjectPath]
1517
+ end
1518
+
1519
+ # ObjectPath ::= GraphNodePath AnnotationPath
1520
+ #
1521
+ # Adds `:Subject` and `:Verb` to data from input.
1522
+ #
1523
+ # Returns patterns and object
1524
+ start_production(:ObjectPath, as_hash: true) do |data|
1525
+ data[:Subject] = prod_data[:Subject]
1526
+ data[:Verb] = prod_data[:Verb]
1527
+ end
1528
+
1529
+ production(:ObjectPath) do |value, data|
1530
+ subject = data[:Subject]
1531
+ verb = data[:Verb]
1532
+ object = value[:GraphNodePath][:object]
1533
+ patterns = if verb.is_a?(SPARQL::Algebra::Query)
1534
+ # It's a path
1535
+ [SPARQL::Algebra::Expression(:path, subject, verb, object)]
1536
+ else
1537
+ [RDF::Query::Pattern.new(subject, verb, object)]
1538
+ end
1539
+ {
1540
+ object: object,
1541
+ pattern: patterns + value[:GraphNodePath][:pattern] + value[:AnnotationPath]
1542
+ }
1543
+ end
1544
+
1545
+ # Path ::= PathAlternative
1546
+ #
1547
+ # Output an IRI or path.
1548
+ production(:Path) do |value|
1549
+ value.last[:PathAlternative]
1550
+ end
1551
+
1552
+ # PathAlternative ::= PathSequence ( '|' PathSequence )*
1553
+ #
1554
+ # Input is `:PathSequence` containing one or more path objects.
1555
+ # Output is the resulting path, containing a nested sequence of `Algebra::Alt` connecting the elements from `:PathSequence`, unless there is only one such element, in which case it is added directly.
1556
+ start_production(:PathAlternative, as_hash: true)
1557
+ production(:PathAlternative) do |value|
1558
+ lhs = value[:PathSequence]
1559
+ while value[:_PathAlternative_1] && !value[:_PathAlternative_1].empty?
1560
+ rhs = value[:_PathAlternative_1].shift
1561
+ lhs = SPARQL::Algebra::Expression[:alt, lhs, rhs]
1562
+ end
1563
+ lhs
1564
+ end
1565
+
1566
+ # (rule _PathAlternative_2 (seq '|' PathSequence))
1567
+ start_production(:_PathAlternative_2, as_hash: true)
1568
+ production(:_PathAlternative_2) do |value|
1569
+ value[:PathSequence]
1570
+ end
1571
+
1572
+ # PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
1573
+ #
1574
+ # Input is `:PathSequence` containing one or more path objects.
1575
+ # Output a path containing a nested sequence of `Algebra::Seq` connecting the elements from `:PathSequence`, unless there is only one such element, in which case it is added directly.
1576
+ start_production(:PathSequence, as_hash: true)
1577
+ production(:PathSequence) do |value|
1578
+ lhs = value[:PathEltOrInverse]
1579
+ while value[:_PathSequence_1] && !value[:_PathSequence_1].empty?
1580
+ rhs = value[:_PathSequence_1].shift
1581
+ lhs = SPARQL::Algebra::Expression[:seq, lhs, rhs]
1582
+ end
1583
+ lhs
1584
+ end
1585
+
1586
+ # (rule _PathSequence_2 (seq '/' PathEltOrInverse))
1587
+ start_production(:_PathSequence_2, as_hash: true)
1588
+ production(:_PathSequence_2) do |value|
1589
+ value[:PathEltOrInverse]
1590
+ end
1591
+
1592
+ # PathElt ::= PathPrimary PathMod?
1593
+ #
1594
+ # (rule PathElt (seq PathPrimary _PathElt_1))
1595
+ # (rule _PathElt_1 (opt PathMod))
1596
+ #
1597
+ # Output is a path, a possibly modified `:PathPrimary`.
1598
+ start_production(:PathElt, as_hash: true)
1599
+ production(:PathElt) do |value|
1600
+ if path_mod = value[:_PathElt_1]
1601
+ # Add primary path to operand
1602
+ op_len = path_mod.operands.length
1603
+ path_mod.operands[op_len-1] = value[:PathPrimary]
1604
+ path_mod
1605
+ else
1606
+ value[:PathPrimary]
1607
+ end
1608
+ end
1609
+
1610
+ # PathEltOrInverse ::= PathElt | '^' PathElt
1611
+ #
1612
+ # Input is `:Path`, or a reversed path if it is an array.
1613
+ # Output is a possibly reversed path.
1614
+ production(:PathEltOrInverse) do |value|
1615
+ if value.is_a?(Array)
1616
+ SPARQL::Algebra::Expression(:reverse, value.last[:PathElt])
1617
+ else
1618
+ value
1619
+ end
1620
+ end
1621
+
1622
+ # PathMod ::= '*' | '?' | '+' | '{' INTEGER? (',' INTEGER?)? '}'
1623
+ #
1624
+ # (rule PathMod (alt '?' '*' '+' _PathMod_1))
1625
+ # (rule _PathMod_1 (seq '{' _PathMod_2 _PathMod_3 '}'))
1626
+ # (rule _PathMod_2 (opt INTEGER))
1627
+ # (rule _PathMod_3 (opt _PathMod_4))
1628
+ # (rule _PathMod_4 (seq ',' _PathMod_5))
1629
+ # (rule _PathMod_5 (opt INTEGER))
1630
+ production(:PathMod) do |value|
1631
+ if value.is_a?(SPARQL::Algebra::Expression)
1632
+ value
1633
+ elsif value
1634
+ # Last operand added in :PathElt
1635
+ SPARQL::Algebra::Expression("path#{value}", RDF.nil)
1636
+ end
1637
+ end
1638
+
1639
+ start_production(:_PathMod_1, as_hash: true)
1640
+ production(:_PathMod_1) do |value|
1641
+ raise Error, "expect property range to have integral elements" if
1642
+ value[:_PathMod_2].nil? && value[:_PathMod_3] == :*
1643
+ min = value[:_PathMod_2] || 0
1644
+ max = value[:_PathMod_3] || min
1645
+
1646
+ # Last operand added in :PathElt
1647
+ SPARQL::Algebra::Expression(:pathRange, min, max, RDF.nil)
1648
+ end
1649
+
1650
+ # (rule _PathMod_4 (seq ',' _PathMod_5))
1651
+ start_production(:_PathMod_4, as_hash: true)
1652
+ production(:_PathMod_4) do |value|
1653
+ value[:_PathMod_5] || :*
1654
+ end
1655
+
1656
+ # PathPrimary ::= iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')'
1657
+ #
1658
+ # (rule PathPrimary (alt iri 'a' _PathPrimary_1 _PathPrimary_2))
1659
+ # (rule _PathPrimary_1 (seq '!' PathNegatedPropertySet))
1660
+ # (rule _PathPrimary_2 (seq '(' Path ')'))
1661
+ start_production(:PathPrimary, insensitive_strings: false)
1662
+ production(:PathPrimary) do |value|
1663
+ if value == 'a'
1664
+ RDF.type.dup.tap {|a| a.lexical = 'a'}
1665
+ else
1666
+ value
1667
+ end
1668
+ end
1669
+
1670
+ # (rule _PathPrimary_1 (seq '!' PathNegatedPropertySet))
1671
+ production(:_PathPrimary_1) {|value| value.last[:PathNegatedPropertySet]}
1672
+
1673
+ # (rule _PathPrimary_2 (seq '(' Path ')'))
1674
+ production(:_PathPrimary_2) {|value| value[1][:Path]}
1675
+
1676
+ # PathNegatedPropertySet ::= PathOneInPropertySet |
1677
+ # '('
1678
+ # ( PathOneInPropertySet
1679
+ # ( '|' PathOneInPropertySet )*
1680
+ # )?
1681
+ # ')'
1682
+ #
1683
+ # (rule PathNegatedPropertySet (alt PathOneInPropertySet _PathNegatedPropertySet_1))
1684
+ # (rule _PathNegatedPropertySet_1 (seq '(' _PathNegatedPropertySet_2 ')'))
1685
+ # (rule _PathNegatedPropertySet_2 (opt _PathNegatedPropertySet_3))
1686
+ # (rule _PathNegatedPropertySet_3
1687
+ # (seq PathOneInPropertySet _PathNegatedPropertySet_4))
1688
+ # (rule _PathNegatedPropertySet_4 (star _PathNegatedPropertySet_5))
1689
+ # (rule _PathNegatedPropertySet_5 (seq '|' PathOneInPropertySet))
1690
+ #
1691
+ production(:PathNegatedPropertySet) do |value|
1692
+ SPARQL::Algebra::Expression(:notoneof, *Array(value))
1693
+ end
1694
+
1695
+ # (rule _PathNegatedPropertySet_1 (seq '(' _PathNegatedPropertySet_2 ')'))
1696
+ production(:_PathNegatedPropertySet_1) do |value|
1697
+ value[1][:_PathNegatedPropertySet_2]
1698
+ end
1699
+
1700
+ # (rule _PathNegatedPropertySet_3
1701
+ # (seq PathOneInPropertySet _PathNegatedPropertySet_4))
1702
+ start_production(:_PathNegatedPropertySet_3, as_hash: true)
1703
+ production(:_PathNegatedPropertySet_3) do |value|
1704
+ value[:_PathNegatedPropertySet_4].unshift(value[:PathOneInPropertySet])
1705
+ end
1706
+
1707
+ # (rule _PathNegatedPropertySet_5 (seq '|' PathOneInPropertySet))
1708
+ production(:_PathNegatedPropertySet_5) do |value|
1709
+ value.last[:PathOneInPropertySet]
1710
+ end
1711
+
1712
+ # PathOneInPropertySet ::= iri | 'a' | '^' ( iri | 'a' )
1713
+ #
1714
+ # (rule PathOneInPropertySet (alt iri 'a' _PathOneInPropertySet_1))
1715
+ # (rule _PathOneInPropertySet_1 (seq '^' _PathOneInPropertySet_2))
1716
+ # (rule _PathOneInPropertySet_2 (alt iri 'a'))
1717
+ start_production(:PathOneInPropertySet, insensitive_strings: false)
1718
+ production(:PathOneInPropertySet) do |value|
1719
+ if value == 'a'
1720
+ RDF.type.dup.tap {|a| a.lexical = 'a'}
1721
+ elsif value.is_a?(RDF::URI)
1722
+ value
1723
+ else
1724
+ SPARQL::Algebra::Expression(:reverse, value.last[:_PathOneInPropertySet_2])
1725
+ end
1726
+ end
1727
+
1728
+ # BlankNodePropertyList ::= '[' PropertyListNotEmpty ']'
1729
+ start_production(:BlankNodePropertyList, as_hash: true) do |data|
1730
+ data[:Subject] = prod_data[:TriplesNode]
1731
+ end
1732
+ production(:BlankNodePropertyList) do |value, data|
1733
+ {
1734
+ object: data[:Subject],
1735
+ pattern: value[:PropertyListNotEmpty]
1736
+ }
1737
+ end
1738
+
1739
+ # TriplesNode ::= Collection | BlankNodePropertyList
1740
+ #
1741
+ # Returns object and patterns
1742
+ start_production(:TriplesNode) do |data|
1743
+ data[:TriplesNode] = bnode
1744
+ end
1745
+ production(:TriplesNode) do |value, data|
1746
+ # Record the node for downstream productions XXX
1747
+ prod_data[:TriplesNode] = data[:TriplesNode]
1748
+
1749
+ value.is_a?(Hash) ? value : {object: data[:TriplesNode], pattern: value}
1750
+ end
1751
+
1752
+ # TriplesNodePath ::= CollectionPath | BlankNodePropertyListPath
1753
+ #
1754
+ # Returns object and patterns
1755
+ start_production(:TriplesNodePath) do |data|
1756
+ # Called after Verb. The prod_data stack should have Subject and Verb elements
1757
+ data[:TriplesNode] = bnode
1758
+ end
1759
+ production(:TriplesNodePath) do |value, data|
1760
+ # Record the node for downstraem productions
1761
+ prod_data[:TriplesNode] = data[:TriplesNode]
1762
+
1763
+ value.is_a?(Hash) ? value : {object: data[:TriplesNode], pattern: value}
1764
+ end
1765
+
1766
+ # BlankNodePropertyListPath ::= '[' PropertyListPathNotEmpty ']'
1767
+ #
1768
+ # Returns object and patterns
1769
+ start_production(:BlankNodePropertyListPath, as_hash: true) do |data|
1770
+ data[:Subject] = prod_data[:TriplesNode]
1771
+ end
1772
+ production(:BlankNodePropertyListPath) do |value, data|
1773
+ {
1774
+ object: data[:Subject],
1775
+ pattern: value[:PropertyListPathNotEmpty]
1776
+ }
1777
+ end
1778
+
1779
+ # Collection ::= '(' GraphNode+ ')'
1780
+ #
1781
+ # (rule Collection (seq '(' _Collection_1 ')'))
1782
+ # (rule _Collection_1 (plus GraphNode))
1783
+ #
1784
+ # Returns patterns
1785
+ start_production(:Collection, as_hash: true) do |data|
1786
+ # Tells the TriplesNode production to collect and not generate statements
1787
+ data[:Subject] = prod_data[:TriplesNode]
1788
+ end
1789
+ production(:Collection) do |value, data|
1790
+ expand_collection(data[:Subject], value[:_Collection_1])
1791
+ end
1792
+
1793
+ # CollectionPath ::= "(" GraphNodePath+ ")"
1794
+ #
1795
+ # (rule CollectionPath (seq '(' _CollectionPath_1 ')'))
1796
+ # (rule _CollectionPath_1 (plus GraphNodePath))
1797
+ #
1798
+ # Returns patterns
1799
+ start_production(:CollectionPath, as_hash: true) do |data|
1800
+ # Tells the TriplesNode production to collect and not generate statements
1801
+ data[:Subject] = prod_data[:TriplesNode]
1802
+ end
1803
+ production(:CollectionPath) do |value, data|
1804
+ expand_collection(data[:Subject], value[:_CollectionPath_1])
1805
+ end
1806
+
1807
+ # AnnotationPath ::= ( Reifier | AnnotationBlockPath )*
1808
+ #
1809
+ # Returns patterns
1810
+ start_production(:AnnotationPath, as_hash: true) do |data|
1811
+ object = data[:_rept_data].first[:GraphNodePath][:object]
1812
+ error("AnnotationPath", "Expected Subject", production: :AnnotationPath) unless prod_data[:Subject]
1813
+ error("AnnotationPath", "Expected Verb", production: :AnnotationPath) unless prod_data[:Verb]
1814
+ error("AnnotationPath", "Expected Object", production: :AnnotationPath) unless object
1815
+ data[:curReifier] = nil
1816
+ data[:TripleTerm] = RDF::Query::Pattern.new(prod_data[:Subject], prod_data[:Verb], object, tripleTerm: true)
1817
+ end
1818
+
1819
+ production(:AnnotationPath) do |value|
1820
+ value.flatten
1821
+ end
1822
+
1823
+ # AnnotationBlockPath ::= '{|' PropertyListPathNotEmpty '|}'
1824
+ #
1825
+ # Beginning the annotationBlock production, if the curReifier is not set, then the curReifier is assigned a fresh RDF blank node and then yields the RDF triple curReifier rdf:reifies curTripleTerm. The curSubject is taken from the curReifier
1826
+ start_production(:AnnotationBlockPath, as_hash: true) do |data|
1827
+ # Store AnnotationPath data for reference in PropertyListPathNotEmpty
1828
+ data[:AnnotationData] = prod_data
1829
+ data[:emit_tt] = prod_data[:curReifier].nil?
1830
+ end
1831
+
1832
+ production(:AnnotationBlockPath) do |value, data|
1833
+ patterns = if data[:emit_tt]
1834
+ reifier = data[:AnnotationData][:curReifier]
1835
+ [RDF::Query::Pattern.new(reifier, RDF.reifies, prod_data[:TripleTerm])]
1836
+ else
1837
+ []
1838
+ end
1839
+ data[:AnnotationData][:curReifier] = nil
1840
+ patterns += value[:PropertyListPathNotEmpty]
1841
+ patterns
1842
+ end
1843
+
1844
+ # Annotation ::= ( Reifier | AnnotationBlock )*
1845
+ #
1846
+ # Returns patterns
1847
+ start_production(:Annotation) do |data|
1848
+ object = data[:_rept_data].first[:GraphNode][:object]
1849
+ error("AnnotationPath", "Expected Subject", production: :AnnotationPath) unless prod_data[:Subject]
1850
+ error("AnnotationPath", "Expected Verb", production: :AnnotationPath) unless prod_data[:Verb]
1851
+ error("AnnotationPath", "Expected Object", production: :AnnotationPath) unless object
1852
+ data[:curReifier] = nil
1853
+ data[:TripleTerm] = RDF::Query::Pattern.new(prod_data[:Subject], prod_data[:Verb], object, tripleTerm: true)
1854
+ end
1855
+
1856
+ production(:Annotation) do |value|
1857
+ value.flatten
1858
+ end
1859
+
1860
+ # AnnotationBlock ::= '{|' PropertyListPathNotEmpty '|}'
1861
+ #
1862
+ # Beginning the annotationBlock production, if the curReifier is not set, then the curReifier is assigned a fresh RDF blank node and then yields the RDF triple curReifier rdf:reifies curTripleTerm. The curSubject is taken from the curReifier
1863
+ start_production(:AnnotationBlock, as_hash: true) do |data|
1864
+ # Store AnnotationPath data for reference in PropertyListPathNotEmpty
1865
+ data[:AnnotationData] = prod_data
1866
+ data[:emit_tt] = prod_data[:curReifier].nil?
1867
+ end
1868
+
1869
+ production(:AnnotationBlock) do |value, data|
1870
+ patterns = []
1871
+ if data[:emit_tt]
1872
+ reifier = data[:AnnotationData][:curReifier]
1873
+ patterns = [RDF::Query::Pattern.new(reifier, RDF.reifies, prod_data[:TripleTerm])]
1874
+ end
1875
+ data[:AnnotationData][:curReifier] = nil
1876
+ patterns += value[:PropertyListNotEmpty]
1877
+ patterns
1878
+ end
1879
+
1880
+ # GraphNode ::= VarOrTerm | TriplesNode
1881
+ #
1882
+ # Returns object and patterns
1883
+ production(:GraphNode) do |value|
1884
+ value.is_a?(Hash) ? value : {object: value, pattern: []}
1885
+ end
1886
+
1887
+ # GraphNodePath ::= VarOrTerm | TriplesNodePath | ReifiedTriple
1888
+ #
1889
+ # Returns object and patterns
1890
+ production(:GraphNodePath) do |value|
1891
+ value.is_a?(Hash) ? value : {object: value, pattern: []}
1892
+ end
1893
+
1894
+ # ReifiedTriple ::= '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
1895
+ #
1896
+ # (rule ReifiedTriple
1897
+ # (seq '<<' ReifiedTripleSubject Verb ReifiedTripleObject _ReifiedTriple_1 '>>'))
1898
+ # (rule _ReifiedTriple_1 (opt Reifier))
1899
+ #
1900
+ # Returns reifier and pattern. Saves reifier in prod_data
1901
+ start_production(:ReifiedTriple, as_hash: true)
1902
+ production(:ReifiedTriple) do |value, data|
1903
+ subject = value[:ReifiedTripleSubject]
1904
+ predicate = value[:Verb]
1905
+ object = value[:ReifiedTripleObject]
1906
+ reifier = data[:curReifier] || bnode
1907
+ prod_data[:Subject] = reifier
1908
+
1909
+ {
1910
+ object: reifier,
1911
+ pattern: [RDF::Query::Pattern.new(
1912
+ reifier,
1913
+ RDF.reifies,
1914
+ RDF::Query::Pattern.new(subject, predicate, object, tripleTerm: true))]
1915
+ }
1916
+ end
1917
+
1918
+ # TripleTerm ::= ::= '<<(' TripleTermSubject Verb TripleTermObject ')>>'
1919
+ #
1920
+ # Input is subject, verb and object.
1921
+ # Output is a triple term.
1922
+ start_production(:TripleTerm, as_hash: true)
1923
+ production(:TripleTerm) do |value|
1924
+ RDF::Query::Pattern.new(value[:TripleTermSubject], value[:Verb], value[:TripleTermObject], tripleTerm: true)
1925
+ end
1926
+
1927
+ # TripleTermData ::= '<<(' TripleTermDataSubject ( iri | 'a' ) TripleTermDataObject ')>>'
1928
+ #
1929
+ # (rule TripleTermData
1930
+ # (seq '<<(' TripleTermDataSubject _TripleTermData_1 TripleTermDataObject ')>>'))
1931
+ # (rule _TripleTermData_1 (alt iri 'a'))
1932
+ start_production(:TripleTermData, as_hash: true)
1933
+ production(:TripleTermData) do |value|
1934
+ RDF::Query::Pattern.new(value[:TripleTermDataSubject], value[:_TripleTermData_1], value[:TripleTermDataObject], tripleTerm: true)
1935
+ end
1936
+
1937
+ # (rule _TripleTermData_1 (alt iri 'a'))
1938
+ production(:_TripleTermData_1) do |value|
1939
+ if value == 'a'
1940
+ RDF.type.dup.tap {|a| a.lexical = 'a'}
1941
+ else
1942
+ value
1943
+ end
1944
+ end
1945
+
1946
+ # Expression ::= ConditionalOrExpression
1947
+ production(:Expression) do |value|
1948
+ value.first[:ConditionalOrExpression]
1949
+ end
1950
+
1951
+ # ConditionalOrExpression ::= ConditionalAndExpression
1952
+ # ( '||' ConditionalAndExpression )*
1953
+ #
1954
+ # (rule ConditionalOrExpression
1955
+ # (seq ConditionalAndExpression _ConditionalOrExpression_1))
1956
+ # (rule _ConditionalOrExpression_1 (star _ConditionalOrExpression_2))
1957
+ start_production(:ConditionalOrExpression, as_hash: true)
1958
+ production(:ConditionalOrExpression) do |value|
1959
+ add_operator_expressions(value[:ConditionalAndExpression], *value[:_ConditionalOrExpression_1])
1960
+ end
1961
+
1962
+ # (rule _ConditionalOrExpression_2 (seq '||' ConditionalAndExpression))
1963
+ production(:_ConditionalOrExpression_2) do |value|
1964
+ [:or, value.last[:ConditionalAndExpression]]
1965
+ end
1966
+
1967
+ # ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )*
1968
+ #
1969
+ # (rule ConditionalAndExpression (seq ValueLogical _ConditionalAndExpression_1))
1970
+ # (rule _ConditionalAndExpression_1 (star _ConditionalAndExpression_2))
1971
+ start_production(:ConditionalAndExpression, as_hash: true)
1972
+ production(:ConditionalAndExpression) do |value|
1973
+ add_operator_expressions(value[:ValueLogical], *value[:_ConditionalAndExpression_1])
1974
+ end
1975
+
1976
+ # (rule _ConditionalAndExpression_2 (seq '&&' ValueLogical))
1977
+ production(:_ConditionalAndExpression_2) do |value|
1978
+ [:and, value.last[:ValueLogical]]
1979
+ end
1980
+
1981
+ # ValueLogical ::= RelationalExpression
1982
+ production(:ValueLogical) do |value|
1983
+ value.first[:RelationalExpression]
1984
+ end
1985
+
1986
+ # RelationalExpression ::= NumericExpression
1987
+ # ( '=' NumericExpression
1988
+ # | '!=' NumericExpression
1989
+ # | '<' NumericExpression
1990
+ # | '>' NumericExpression
1991
+ # | '<=' NumericExpression
1992
+ # | '>=' NumericExpression
1993
+ # | 'IN' ExpressionList
1994
+ # | 'NOT' 'IN' ExpressionList
1995
+ # )?
1996
+ #
1997
+ # (rule RelationalExpression (seq NumericExpression _RelationalExpression_1))
1998
+ # (rule _RelationalExpression_1 (opt _RelationalExpression_2))
1999
+ # (rule _RelationalExpression_2
2000
+ # (alt _RelationalExpression_3 _RelationalExpression_4 _RelationalExpression_5
2001
+ # _RelationalExpression_6 _RelationalExpression_7 _RelationalExpression_8
2002
+ # _RelationalExpression_9 _RelationalExpression_10 ))
2003
+ # (rule _RelationalExpression_3 (seq '=' NumericExpression))
2004
+ # (rule _RelationalExpression_4 (seq '!=' NumericExpression))
2005
+ # (rule _RelationalExpression_5 (seq '<' NumericExpression))
2006
+ # (rule _RelationalExpression_6 (seq '>' NumericExpression))
2007
+ # (rule _RelationalExpression_7 (seq '<=' NumericExpression))
2008
+ # (rule _RelationalExpression_8 (seq '>=' NumericExpression))
2009
+ # (rule _RelationalExpression_9 (seq 'IN' ExpressionList))
2010
+ # (rule _RelationalExpression_10 (seq 'NOT' 'IN' ExpressionList))
2011
+ #
2012
+ start_production(:RelationalExpression, as_hash: true)
2013
+ production(:RelationalExpression) do |value|
2014
+ if Array(value[:_RelationalExpression_1]).empty?
2015
+ value[:NumericExpression]
2016
+ else
2017
+ comparator, rhs = value[:_RelationalExpression_1]
2018
+ SPARQL::Algebra::Expression.for(comparator, value[:NumericExpression], *Array(rhs))
2019
+ end
2020
+ end
2021
+
2022
+ # (rule _RelationalExpression_2
2023
+ # (alt _RelationalExpression_3 _RelationalExpression_4 _RelationalExpression_5
2024
+ # _RelationalExpression_6 _RelationalExpression_7 _RelationalExpression_8
2025
+ # _RelationalExpression_9 _RelationalExpression_10 ))
2026
+ production(:_RelationalExpression_2) do |value|
2027
+ if value.last.is_a?(Hash)
2028
+ comparator = value.first.values.first
2029
+ rhs = value.last.values.first
2030
+ [comparator, rhs]
2031
+ else
2032
+ value
2033
+ end
2034
+ end
2035
+
2036
+ # (rule _RelationalExpression_9 (seq 'IN' ExpressionList))
2037
+ start_production(:_RelationalExpression_9, as_hash: true, insensitve_strings: :upper)
2038
+ production(:_RelationalExpression_9) do |value|
2039
+ [:in, value[:ExpressionList]]
2040
+ end
2041
+
2042
+ # (rule _RelationalExpression_10 (seq 'NOT' 'IN' ExpressionList))
2043
+ start_production(:_RelationalExpression_10, as_hash: true, insensitve_strings: :upper)
2044
+ production(:_RelationalExpression_10) do |value|
2045
+ [:notin, value[:ExpressionList]]
2046
+ end
2047
+
2048
+ # NumericExpression::= AdditiveExpression
2049
+ production(:NumericExpression) do |value|
2050
+ value.first[:AdditiveExpression]
2051
+ end
2052
+
2053
+ # AdditiveExpression ::= MultiplicativeExpression
2054
+ # ( '+' MultiplicativeExpression
2055
+ # | '-' MultiplicativeExpression
2056
+ # | ( NumericLiteralPositive
2057
+ # | NumericLiteralNegative )
2058
+ # ( ( '*' UnaryExpression )
2059
+ # | ( '/' UnaryExpression ) )*
2060
+ # )*
2061
+ start_production(:AdditiveExpression, as_hash: true)
2062
+ production(:AdditiveExpression) do |value|
2063
+ add_operator_expressions(value[:MultiplicativeExpression], *value[:_AdditiveExpression_1])
2064
+ end
2065
+
2066
+ # (rule _AdditiveExpression_3 (seq '+' MultiplicativeExpression))
2067
+ production(:_AdditiveExpression_3) do |value|
2068
+ [:+, value.last[:MultiplicativeExpression]]
2069
+ end
2070
+
2071
+ # (rule _AdditiveExpression_4 (seq '-' MultiplicativeExpression))
2072
+ production(:_AdditiveExpression_4) do |value|
2073
+ [:-, value.last[:MultiplicativeExpression]]
2074
+ end
2075
+
2076
+ # (rule _AdditiveExpression_5 (seq _AdditiveExpression_6 _AdditiveExpression_7))
2077
+ # (rule _AdditiveExpression_6 (alt NumericLiteralPositive NumericLiteralNegative))
2078
+ # (rule _AdditiveExpression_7 (star _AdditiveExpression_8))
2079
+ # (rule _AdditiveExpression_8 (alt _AdditiveExpression_9 _AdditiveExpression_10))
2080
+ start_production(:_AdditiveExpression_5, as_hash: true)
2081
+ production(:_AdditiveExpression_5) do |value|
2082
+ op = value[:_AdditiveExpression_6] < 0 ? :- : :+
2083
+ lhs = value[:_AdditiveExpression_6].abs + 0
2084
+ [op, add_operator_expressions(lhs, *value[:_AdditiveExpression_7])]
2085
+ end
2086
+
2087
+ # (rule _AdditiveExpression_9 (seq '*' UnaryExpression))
2088
+ production(:_AdditiveExpression_9) do |value|
2089
+ [:*, value.last[:UnaryExpression]]
2090
+ end
2091
+
2092
+ # (rule _AdditiveExpression_10 (seq '/' UnaryExpression))
2093
+ production(:_AdditiveExpression_10) do |value|
2094
+ [:/, value.last[:UnaryExpression]]
2095
+ end
2096
+
2097
+ # MultiplicativeExpression ::= UnaryExpression
2098
+ # ( '*' UnaryExpression
2099
+ # | '/' UnaryExpression )*
2100
+ start_production(:MultiplicativeExpression, as_hash: true)
2101
+ production(:MultiplicativeExpression) do |value|
2102
+ add_operator_expressions(value[:UnaryExpression], *value[:_MultiplicativeExpression_1])
2103
+ end
2104
+
2105
+ # (rule _MultiplicativeExpression_3 (seq '*' UnaryExpression))
2106
+ production(:_MultiplicativeExpression_3) do |value|
2107
+ [:*, value.last[:UnaryExpression]]
2108
+ end
2109
+
2110
+ # (rule _MultiplicativeExpression_4 (seq '/' UnaryExpression))
2111
+ production(:_MultiplicativeExpression_4) do |value|
2112
+ [:/, value.last[:UnaryExpression]]
2113
+ end
2114
+
2115
+ # UnaryExpression ::= '!' PrimaryExpression
2116
+ # | '+' PrimaryExpression
2117
+ # | '-' PrimaryExpression
2118
+ # | PrimaryExpression
2119
+ #
2120
+ # (rule UnaryExpression
2121
+ # (alt _UnaryExpression_1 _UnaryExpression_2 _UnaryExpression_3 PrimaryExpression))
2122
+ # (rule _UnaryExpression_1 (seq '!' PrimaryExpression))
2123
+ # (rule _UnaryExpression_2 (seq '+' PrimaryExpression))
2124
+ # (rule _UnaryExpression_3 (seq '-' PrimaryExpression))
2125
+
2126
+ # (rule _UnaryExpression_1 (seq '!' PrimaryExpression))
2127
+ production(:_UnaryExpression_1) do |value|
2128
+ SPARQL::Algebra::Expression[:not, value.last[:PrimaryExpression]]
2129
+ end
2130
+
2131
+ # (rule _UnaryExpression_2 (seq '+' PrimaryExpression))
2132
+ production(:_UnaryExpression_2) do |value|
2133
+ value.last[:PrimaryExpression]
2134
+ end
2135
+
2136
+ # (rule _UnaryExpression_3 (seq '-' PrimaryExpression))
2137
+ production(:_UnaryExpression_3) do |value|
2138
+ expr = value.last[:PrimaryExpression]
2139
+ if expr.is_a?(RDF::Literal::Numeric)
2140
+ -expr
2141
+ else
2142
+ SPARQL::Algebra::Expression[:"-", expr]
2143
+ end
2144
+ end
2145
+
2146
+ # ExprTripleTerm ::= '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
2147
+ start_production(:ExprTripleTerm, as_hash: true)
2148
+ production(:ExprTripleTerm) do |value|
2149
+ subject = value[:ExprTripleTermSubject]
2150
+ predicate = value[:Verb]
2151
+ object = value[:ExprTripleTermObject]
2152
+ RDF::Query::Pattern.new(subject, predicate, object, tripleTerm: true)
2153
+ end
2154
+
2155
+ # BrackettedExpression ::= '(' Expression ')'
2156
+ production(:BrackettedExpression) do |value|
2157
+ value[1][:Expression]
2158
+ end
2159
+
2160
+ # (rule _BuiltInCall_1 (seq 'STR' '(' Expression ')'))
2161
+ start_production(:_BuiltInCall_1, as_hash: true)
2162
+ production(:_BuiltInCall_1) do |value|
2163
+ SPARQL::Algebra::Operator::Str.new(value[:Expression])
2164
+ end
2165
+
2166
+ # (rule _BuiltInCall_2 (seq 'LANG' '(' Expression ')'))
2167
+ start_production(:_BuiltInCall_2, as_hash: true)
2168
+ production(:_BuiltInCall_2) do |value|
2169
+ SPARQL::Algebra::Operator::Lang.new(value[:Expression])
2170
+ end
2171
+
2172
+ # (rule _BuiltInCall_3 (seq 'LANGMATCHES' '(' Expression ',' Expression ')'))
2173
+ start_production(:_BuiltInCall_3, as_hash: false)
2174
+ production(:_BuiltInCall_3) do |value|
2175
+ SPARQL::Algebra::Operator::LangMatches.new(value[2][:Expression], value[4][:Expression])
2176
+ end
2177
+
2178
+ # (rule _BuiltInCall_4 (seq 'DATATYPE' '(' Expression ')'))
2179
+ start_production(:_BuiltInCall_4, as_hash: true)
2180
+ production(:_BuiltInCall_4) do |value|
2181
+ SPARQL::Algebra::Operator::Datatype.new(value[:Expression])
2182
+ end
2183
+
2184
+ # (rule _BuiltInCall_5 (seq 'BOUND' '(' Var ')'))
2185
+ start_production(:_BuiltInCall_5, as_hash: true)
2186
+ production(:_BuiltInCall_5) do |value|
2187
+ SPARQL::Algebra::Operator::Bound.new(value[:Var])
2188
+ end
2189
+
2190
+ # (rule _BuiltInCall_6 (seq 'IRI' '(' Expression ')'))
2191
+ start_production(:_BuiltInCall_6, as_hash: true)
2192
+ production(:_BuiltInCall_6) do |value|
2193
+ SPARQL::Algebra::Operator::IRI.new(value[:Expression])
2194
+ end
2195
+
2196
+ # (rule _BuiltInCall_7 (seq 'URI' '(' Expression ')'))
2197
+ start_production(:_BuiltInCall_7, as_hash: true)
2198
+ production(:_BuiltInCall_7) do |value|
2199
+ SPARQL::Algebra::Operator::IRI.new(value[:Expression])
2200
+ end
2201
+
2202
+ # (rule _BuiltInCall_8 (seq 'BNODE' _BuiltInCall_57))
2203
+ # (rule _BuiltInCall_57 (alt _BuiltInCall_58 NIL))
2204
+ # (rule _BuiltInCall_58 (seq '(' Expression ')'))
2205
+ start_production(:_BuiltInCall_8, as_hash: true)
2206
+ production(:_BuiltInCall_8) do |value|
2207
+ if value[:_BuiltInCall_57].is_a?(RDF::Term)
2208
+ SPARQL::Algebra::Operator::BNode.new
2209
+ else
2210
+ SPARQL::Algebra::Operator::BNode.new(value[:_BuiltInCall_57][1][:Expression])
2211
+ end
2212
+ end
2213
+
2214
+ # (rule _BuiltInCall_9 (seq 'RAND' NIL))
2215
+ start_production(:_BuiltInCall_9, as_hash: true)
2216
+ production(:_BuiltInCall_9) do |value|
2217
+ SPARQL::Algebra::Operator::Rand.new
2218
+ end
2219
+
2220
+ # (rule _BuiltInCall_10 (seq 'ABS' '(' Expression ')'))
2221
+ start_production(:_BuiltInCall_10, as_hash: true)
2222
+ production(:_BuiltInCall_10) do |value|
2223
+ SPARQL::Algebra::Operator::Abs.new(value[:Expression])
2224
+ end
2225
+
2226
+ # (rule _BuiltInCall_11 (seq 'CEIL' '(' Expression ')'))
2227
+ start_production(:_BuiltInCall_11, as_hash: true)
2228
+ production(:_BuiltInCall_11) do |value|
2229
+ SPARQL::Algebra::Operator::Ceil.new(value[:Expression])
2230
+ end
2231
+
2232
+ # (rule _BuiltInCall_12 (seq 'FLOOR' '(' Expression ')'))
2233
+ start_production(:_BuiltInCall_12, as_hash: true)
2234
+ production(:_BuiltInCall_12) do |value|
2235
+ SPARQL::Algebra::Operator::Floor.new(value[:Expression])
2236
+ end
2237
+
2238
+ # (rule _BuiltInCall_13 (seq 'ROUND' '(' Expression ')'))
2239
+ start_production(:_BuiltInCall_13, as_hash: true)
2240
+ production(:_BuiltInCall_13) do |value|
2241
+ SPARQL::Algebra::Operator::Round.new(value[:Expression])
2242
+ end
2243
+
2244
+ # (rule _BuiltInCall_14 (seq 'CONCAT' ExpressionList))
2245
+ start_production(:_BuiltInCall_14, as_hash: true)
2246
+ production(:_BuiltInCall_14) do |value|
2247
+ SPARQL::Algebra::Operator::Concat.new(*value[:ExpressionList])
2248
+ end
2249
+
2250
+ # (rule _BuiltInCall_15 (seq 'STRLEN' '(' Expression ')'))
2251
+ start_production(:_BuiltInCall_15, as_hash: true)
2252
+ production(:_BuiltInCall_15) do |value|
2253
+ SPARQL::Algebra::Operator::StrLen.new(value[:Expression])
2254
+ end
2255
+
2256
+ # (rule _BuiltInCall_16 (seq 'UCASE' '(' Expression ')'))
2257
+ start_production(:_BuiltInCall_16, as_hash: true)
2258
+ production(:_BuiltInCall_16) do |value|
2259
+ SPARQL::Algebra::Operator::UCase.new(value[:Expression])
2260
+ end
2261
+
2262
+ # (rule _BuiltInCall_17 (seq 'LCASE' '(' Expression ')'))
2263
+ start_production(:_BuiltInCall_17, as_hash: true)
2264
+ production(:_BuiltInCall_17) do |value|
2265
+ SPARQL::Algebra::Operator::LCase.new(value[:Expression])
2266
+ end
2267
+
2268
+ # (rule _BuiltInCall_18 (seq 'ENCODE_FOR_URI' '(' Expression ')'))
2269
+ start_production(:_BuiltInCall_18, as_hash: true)
2270
+ production(:_BuiltInCall_18) do |value|
2271
+ SPARQL::Algebra::Operator::EncodeForURI.new(value[:Expression])
2272
+ end
2273
+
2274
+ # (rule _BuiltInCall_19 (seq 'CONTAINS' '(' Expression ',' Expression ')'))
2275
+ production(:_BuiltInCall_19) do |value|
2276
+ SPARQL::Algebra::Operator::Contains.new(value[2][:Expression], value[4][:Expression])
2277
+ end
2278
+
2279
+ # (rule _BuiltInCall_20 (seq 'STRSTARTS' '(' Expression ',' Expression ')'))
2280
+ production(:_BuiltInCall_20) do |value|
2281
+ SPARQL::Algebra::Operator::StrStarts.new(value[2][:Expression], value[4][:Expression])
2282
+ end
2283
+
2284
+ # (rule _BuiltInCall_21 (seq 'STRENDS' '(' Expression ',' Expression ')'))
2285
+ production(:_BuiltInCall_21) do |value|
2286
+ SPARQL::Algebra::Operator::StrEnds.new(value[2][:Expression], value[4][:Expression])
2287
+ end
2288
+
2289
+ # (rule _BuiltInCall_22 (seq 'STRBEFORE' '(' Expression ',' Expression ')'))
2290
+ production(:_BuiltInCall_22) do |value|
2291
+ SPARQL::Algebra::Operator::StrBefore.new(value[2][:Expression], value[4][:Expression])
2292
+ end
2293
+
2294
+ # (rule _BuiltInCall_23 (seq 'STRAFTER' '(' Expression ',' Expression ')'))
2295
+ production(:_BuiltInCall_23) do |value|
2296
+ SPARQL::Algebra::Operator::StrAfter.new(value[2][:Expression], value[4][:Expression])
2297
+ end
2298
+
2299
+ # (rule _BuiltInCall_24 (seq 'YEAR' '(' Expression ')'))
2300
+ start_production(:_BuiltInCall_24, as_hash: true)
2301
+ production(:_BuiltInCall_24) do |value|
2302
+ SPARQL::Algebra::Operator::Year.new(value[:Expression])
2303
+ end
2304
+
2305
+ # (rule _BuiltInCall_25 (seq 'MONTH' '(' Expression ')'))
2306
+ start_production(:_BuiltInCall_25, as_hash: true)
2307
+ production(:_BuiltInCall_25) do |value|
2308
+ SPARQL::Algebra::Operator::Month.new(value[:Expression])
2309
+ end
2310
+
2311
+ # (rule _BuiltInCall_26 (seq 'DAY' '(' Expression ')'))
2312
+ start_production(:_BuiltInCall_26, as_hash: true)
2313
+ production(:_BuiltInCall_26) do |value|
2314
+ SPARQL::Algebra::Operator::Day.new(value[:Expression])
2315
+ end
2316
+
2317
+ # (rule _BuiltInCall_27 (seq 'HOURS' '(' Expression ')'))
2318
+ start_production(:_BuiltInCall_27, as_hash: true)
2319
+ production(:_BuiltInCall_27) do |value|
2320
+ SPARQL::Algebra::Operator::Hours.new(value[:Expression])
2321
+ end
2322
+
2323
+ # (rule _BuiltInCall_28 (seq 'MINUTES' '(' Expression ')'))
2324
+ start_production(:_BuiltInCall_28, as_hash: true)
2325
+ production(:_BuiltInCall_28) do |value|
2326
+ SPARQL::Algebra::Operator::Minutes.new(value[:Expression])
2327
+ end
2328
+
2329
+ # (rule _BuiltInCall_29 (seq 'SECONDS' '(' Expression ')'))
2330
+ start_production(:_BuiltInCall_29, as_hash: true)
2331
+ production(:_BuiltInCall_29) do |value|
2332
+ SPARQL::Algebra::Operator::Seconds.new(value[:Expression])
2333
+ end
2334
+
2335
+ # (rule _BuiltInCall_30 (seq 'TIMEZONE' '(' Expression ')'))
2336
+ start_production(:_BuiltInCall_30, as_hash: true)
2337
+ production(:_BuiltInCall_30) do |value|
2338
+ SPARQL::Algebra::Operator::Timezone.new(value[:Expression])
2339
+ end
2340
+
2341
+ # (rule _BuiltInCall_31 (seq 'TZ' '(' Expression ')'))
2342
+ start_production(:_BuiltInCall_31, as_hash: true)
2343
+ production(:_BuiltInCall_31) do |value|
2344
+ SPARQL::Algebra::Operator::TZ.new(value[:Expression])
2345
+ end
2346
+
2347
+ # (rule _BuiltInCall_32 (seq 'NOW' NIL))
2348
+ start_production(:_BuiltInCall_32, as_hash: true)
2349
+ production(:_BuiltInCall_32) do |value|
2350
+ SPARQL::Algebra::Operator::Now.new
2351
+ end
2352
+
2353
+ # (rule _BuiltInCall_33 (seq 'UUID' NIL))
2354
+ start_production(:_BuiltInCall_33, as_hash: true)
2355
+ production(:_BuiltInCall_33) do |value|
2356
+ SPARQL::Algebra::Operator::UUID.new
2357
+ end
2358
+
2359
+ # (rule _BuiltInCall_34 (seq 'STRUUID' NIL))
2360
+ start_production(:_BuiltInCall_34, as_hash: true)
2361
+ production(:_BuiltInCall_34) do |value|
2362
+ SPARQL::Algebra::Operator::StrUUID.new
2363
+ end
2364
+
2365
+ # (rule _BuiltInCall_35 (seq 'MD5' '(' Expression ')'))
2366
+ start_production(:_BuiltInCall_35, as_hash: true)
2367
+ production(:_BuiltInCall_35) do |value|
2368
+ SPARQL::Algebra::Operator::MD5.new(value[:Expression])
2369
+ end
2370
+
2371
+ # (rule _BuiltInCall_36 (seq 'SHA1' '(' Expression ')'))
2372
+ start_production(:_BuiltInCall_36, as_hash: true)
2373
+ production(:_BuiltInCall_36) do |value|
2374
+ SPARQL::Algebra::Operator::SHA1.new(value[:Expression])
2375
+ end
2376
+
2377
+ # (rule _BuiltInCall_37 (seq 'SHA224' '(' Expression ')'))
2378
+ start_production(:_BuiltInCall_37, as_hash: true)
2379
+ production(:_BuiltInCall_37) do |value|
2380
+ SPARQL::Algebra::Operator::SHA224.new(value[:Expression])
2381
+ end
2382
+
2383
+ # (rule _BuiltInCall_38 (seq 'SHA256' '(' Expression ')'))
2384
+ start_production(:_BuiltInCall_38, as_hash: true)
2385
+ production(:_BuiltInCall_38) do |value|
2386
+ SPARQL::Algebra::Operator::SHA256.new(value[:Expression])
2387
+ end
2388
+
2389
+ # (rule _BuiltInCall_39 (seq 'SHA384' '(' Expression ')'))
2390
+ start_production(:_BuiltInCall_39, as_hash: true)
2391
+ production(:_BuiltInCall_39) do |value|
2392
+ SPARQL::Algebra::Operator::SHA384.new(value[:Expression])
2393
+ end
2394
+
2395
+ # (rule _BuiltInCall_40 (seq 'SHA512' '(' Expression ')'))
2396
+ start_production(:_BuiltInCall_40, as_hash: true)
2397
+ production(:_BuiltInCall_40) do |value|
2398
+ SPARQL::Algebra::Operator::SHA512.new(value[:Expression])
2399
+ end
2400
+
2401
+ # (rule _BuiltInCall_41 (seq 'COALESCE' ExpressionList))
2402
+ start_production(:_BuiltInCall_41, as_hash: true)
2403
+ production(:_BuiltInCall_41) do |value|
2404
+ SPARQL::Algebra::Operator::Coalesce.new(*value[:ExpressionList])
2405
+ end
2406
+
2407
+ # (rule _BuiltInCall_42 (seq 'IF' '(' Expression ',' Expression ',' Expression ')'))
2408
+ production(:_BuiltInCall_42) do |value|
2409
+ SPARQL::Algebra::Operator::If.new(value[2][:Expression], value[4][:Expression], value[6][:Expression])
2410
+ end
2411
+
2412
+ # (rule _BuiltInCall_43 (seq 'STRLANG' '(' Expression ',' Expression ')'))
2413
+ production(:_BuiltInCall_43) do |value|
2414
+ SPARQL::Algebra::Operator::StrLang.new(value[2][:Expression], value[4][:Expression])
2415
+ end
2416
+
2417
+ # (rule _BuiltInCall_44 (seq 'STRDT' '(' Expression ',' Expression ')'))
2418
+ production(:_BuiltInCall_44) do |value|
2419
+ SPARQL::Algebra::Operator::StrDT.new(value[2][:Expression], value[4][:Expression])
2420
+ end
2421
+
2422
+ # (rule _BuiltInCall_45 (seq 'sameTerm' '(' Expression ',' Expression ')'))
2423
+ production(:_BuiltInCall_45) do |value|
2424
+ SPARQL::Algebra::Operator::SameTerm.new(value[2][:Expression], value[4][:Expression])
2425
+ end
2426
+
2427
+ # (rule _BuiltInCall_46 (seq 'isIRI' '(' Expression ')'))
2428
+ start_production(:_BuiltInCall_46, as_hash: true)
2429
+ production(:_BuiltInCall_46) do |value|
2430
+ SPARQL::Algebra::Operator::IsIRI.new(value[:Expression])
2431
+ end
2432
+
2433
+ # (rule _BuiltInCall_47 (seq 'isURI' '(' Expression ')'))
2434
+ start_production(:_BuiltInCall_47, as_hash: true)
2435
+ production(:_BuiltInCall_47) do |value|
2436
+ SPARQL::Algebra::Operator::IsURI.new(value[:Expression])
2437
+ end
2438
+
2439
+ # (rule _BuiltInCall_48 (seq 'isBLANK' '(' Expression ')'))
2440
+ start_production(:_BuiltInCall_48, as_hash: true)
2441
+ production(:_BuiltInCall_48) do |value|
2442
+ SPARQL::Algebra::Operator::IsBlank.new(value[:Expression])
2443
+ end
2444
+
2445
+ # (rule _BuiltInCall_49 (seq 'isLITERAL' '(' Expression ')'))
2446
+ start_production(:_BuiltInCall_49, as_hash: true)
2447
+ production(:_BuiltInCall_49) do |value|
2448
+ SPARQL::Algebra::Operator::IsLiteral.new(value[:Expression])
2449
+ end
2450
+
2451
+ # (rule _BuiltInCall_50 (seq 'isNUMERIC' '(' Expression ')'))
2452
+ start_production(:_BuiltInCall_50, as_hash: true)
2453
+ production(:_BuiltInCall_50) do |value|
2454
+ SPARQL::Algebra::Operator::IsNumeric.new(value[:Expression])
2455
+ end
2456
+
2457
+ # (rule _BuiltInCall_51 (seq 'ADJUST' '(' Expression ',' Expression ')'))
2458
+ production(:_BuiltInCall_51) do |value|
2459
+ SPARQL::Algebra::Operator::Adjust.new(value[2][:Expression], value[4][:Expression])
2460
+ end
2461
+
2462
+ # (rule _BuiltInCall_52 (seq 'isTRIPLE' '(' Expression ')'))
2463
+ start_production(:_BuiltInCall_52, as_hash: true)
2464
+ production(:_BuiltInCall_52) do |value|
2465
+ SPARQL::Algebra::Operator::IsTriple.new(value[:Expression])
2466
+ end
2467
+
2468
+ # (rule _BuiltInCall_53
2469
+ # (seq 'TRIPLE' '(' Expression ',' Expression ',' Expression ')'))
2470
+ production(:_BuiltInCall_53) do |value|
2471
+ SPARQL::Algebra::Operator::Triple.new(value[2][:Expression], value[4][:Expression], value[6][:Expression])
2472
+ end
2473
+
2474
+ # (rule _BuiltInCall_54 (seq 'SUBJECT' '(' Expression ')'))
2475
+ start_production(:_BuiltInCall_54, as_hash: true)
2476
+ production(:_BuiltInCall_54) do |value|
2477
+ SPARQL::Algebra::Operator::Subject.new(value[:Expression])
2478
+ end
2479
+
2480
+ # (rule _BuiltInCall_55 (seq 'PREDICATE' '(' Expression ')'))
2481
+ start_production(:_BuiltInCall_55, as_hash: true)
2482
+ production(:_BuiltInCall_55) do |value|
2483
+ SPARQL::Algebra::Operator::Predicate.new(value[:Expression])
2484
+ end
2485
+
2486
+ # (rule _BuiltInCall_56 (seq 'OBJECT' '(' Expression ')'))
2487
+ start_production(:_BuiltInCall_56, as_hash: true)
2488
+ production(:_BuiltInCall_56) do |value|
2489
+ SPARQL::Algebra::Operator::Object.new(value[:Expression])
2490
+ end
2491
+
2492
+
2493
+ # RegexExpression ::= 'REGEX' '(' Expression ',' Expression
2494
+ # ( ',' Expression )? ')'
2495
+ production(:RegexExpression) do |value|
2496
+ expr_list = [value[2][:Expression], value[4][:Expression]]
2497
+ if value[5][:_RegexExpression_1]
2498
+ expr_list << value[5][:_RegexExpression_1].last[:Expression]
2499
+ end
2500
+ SPARQL::Algebra::Operator::Regex.new(*expr_list)
2501
+ end
2502
+
2503
+ # SubstringExpression ::= 'SUBSTR'
2504
+ # '(' Expression ',' Expression
2505
+ # ( ',' Expression )? ')'
2506
+ production(:SubstringExpression) do |value|
2507
+ expr_list = [value[2][:Expression], value[4][:Expression]]
2508
+ if value[5][:_SubstringExpression_1]
2509
+ expr_list << value[5][:_SubstringExpression_1].last[:Expression]
2510
+ end
2511
+ SPARQL::Algebra::Operator::SubStr.new(*expr_list)
2512
+ end
2513
+
2514
+ # StrReplaceExpression ::= 'REPLACE'
2515
+ # '(' Expression ','
2516
+ # Expression ',' Expression
2517
+ # ( ',' Expression )? ')'
2518
+ production(:StrReplaceExpression) do |value|
2519
+ expr_list = [value[2][:Expression], value[4][:Expression], value[6][:Expression]]
2520
+ if value[7][:_StrReplaceExpression_1]
2521
+ expr_list << value[7][:_StrReplaceExpression_1].last[:Expression]
2522
+ end
2523
+ SPARQL::Algebra::Operator::Replace.new(*expr_list)
2524
+ end
2525
+
2526
+ # ExistsFunc ::= 'EXISTS' GroupGraphPattern
2527
+ start_production(:ExistsFunc, as_hash: true)
2528
+ production(:ExistsFunc) do |value|
2529
+ SPARQL::Algebra::Operator::Exists.new(value&.dig(:GroupGraphPattern, :query))
2530
+ end
2531
+
2532
+ # NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern
2533
+ start_production(:NotExistsFunc, as_hash: true)
2534
+ production(:NotExistsFunc) do |value|
2535
+ SPARQL::Algebra::Operator::NotExists.new(value&.dig(:GroupGraphPattern, :query))
2536
+ end
2537
+
2538
+ # Aggregate ::= 'COUNT' '(' 'DISTINCT'? ( '*' | Expression ) ')'
2539
+ # | 'SUM' '(' 'DISTINCT'? Expression ')'
2540
+ # | 'MIN' '(' 'DISTINCT'? Expression ')'
2541
+ # | 'MAX' '(' 'DISTINCT'? Expression ')'
2542
+ # | 'AVG' '(' 'DISTINCT'? Expression ')'
2543
+ # | 'SAMPLE' '(' 'DISTINCT'? Expression ')'
2544
+ # | 'GROUP_CONCAT' '(' 'DISTINCT'? Expression
2545
+ # ( ';' 'SEPARATOR' '=' String )? ')'
2546
+ production(:Aggregate) do |value|
2547
+ SPARQL::Algebra::Expression.for(*value)
2548
+ end
2549
+
2550
+ # (rule _Aggregate_1 (seq 'COUNT' '(' _Aggregate_8 _Aggregate_9 ')'))
2551
+ start_production(:_Aggregate_1, as_hash: true, insensitive_strings: :upper)
2552
+ production(:_Aggregate_1) do |value|
2553
+ expr = value[:_Aggregate_9] unless value[:_Aggregate_9] == '*'
2554
+ [:count, (value[:_Aggregate_8] ? :distinct : nil), expr].compact
2555
+ end
2556
+
2557
+ # (rule _Aggregate_2 (seq 'SUM' '(' _Aggregate_10 Expression ')'))
2558
+ start_production(:_Aggregate_2, as_hash: true, insensitive_strings: :upper)
2559
+ production(:_Aggregate_2) do |value|
2560
+ [:sum, (value[:_Aggregate_10] ? :distinct : nil), value[:Expression]].compact
2561
+ end
2562
+
2563
+ # (rule _Aggregate_3 (seq 'MIN' '(' _Aggregate_11 Expression ')'))
2564
+ start_production(:_Aggregate_3, as_hash: true, insensitive_strings: :upper)
2565
+ production(:_Aggregate_3) do |value|
2566
+ [:min, (value[:_Aggregate_11] ? :distinct : nil), value[:Expression]].compact
2567
+ end
2568
+
2569
+ # (rule _Aggregate_4 (seq 'MAX' '(' _Aggregate_12 Expression ')'))
2570
+ start_production(:_Aggregate_4, as_hash: true, insensitive_strings: :upper)
2571
+ production(:_Aggregate_4) do |value|
2572
+ [:max, (value[:_Aggregate_12] ? :distinct : nil), value[:Expression]].compact
2573
+ end
2574
+
2575
+ # (rule _Aggregate_5 (seq 'AVG' '(' _Aggregate_13 Expression ')'))
2576
+ start_production(:_Aggregate_5, as_hash: true, insensitive_strings: :upper)
2577
+ production(:_Aggregate_5) do |value|
2578
+ [:avg, (value[:_Aggregate_13] ? :distinct : nil), value[:Expression]].compact
2579
+ end
2580
+
2581
+ # (rule _Aggregate_6 (seq 'SAMPLE' '(' _Aggregate_14 Expression ')'))
2582
+ start_production(:_Aggregate_6, as_hash: true, insensitive_strings: :upper)
2583
+ production(:_Aggregate_6) do |value|
2584
+ [:sample, (value[:_Aggregate_14] ? :distinct : nil), value[:Expression]].compact
2585
+ end
2586
+
2587
+ # (rule _Aggregate_7
2588
+ # (seq 'GROUP_CONCAT' '(' _Aggregate_15 Expression _Aggregate_16 ')'))
2589
+ start_production(:_Aggregate_7, as_hash: true, insensitive_strings: :upper)
2590
+ production(:_Aggregate_7) do |value|
2591
+ separator = value&.dig(:_Aggregate_16, :String)
2592
+ [:group_concat,
2593
+ (value[:_Aggregate_15] ? :distinct : nil),
2594
+ ([:separator, separator] if separator),
2595
+ value[:Expression]
2596
+ ].compact
2597
+ end
2598
+
2599
+ # (rule _Aggregate_17 (seq ';' 'SEPARATOR' '=' String))
2600
+ start_production(:_Aggregate_17, as_hash: true, insensitive_strings: :upper)
2601
+
2602
+ # iriOrFunction ::= iri ArgList?
2603
+ #
2604
+ # (rule iriOrFunction (seq iri _iriOrFunction_1))
2605
+ # (rule _iriOrFunction_1 (opt ArgList))
2606
+ start_production(:iriOrFunction, as_hash: true)
2607
+ production(:iriOrFunction) do |value|
2608
+ if value[:_iriOrFunction_1]
2609
+ SPARQL::Algebra::Operator::FunctionCall.new(value[:iri], *value[:_iriOrFunction_1])
2610
+ else
2611
+ value[:iri]
2612
+ end
2613
+ end
2614
+
2615
+ # RDFLiteral ::= String ( LANG_DIR | '^^' iri )?
2616
+ start_production(:RDFLiteral, as_hash: true)
2617
+ production(:RDFLiteral) do |value|
2618
+ str = value[:String]
2619
+ dt = value[:_RDFLiteral_1] if value[:_RDFLiteral_1].is_a?(RDF::URI)
2620
+ lang = value[:_RDFLiteral_1] if value[:_RDFLiteral_1].is_a?(String)
2621
+ RDF::Literal.new(str, datatype: dt, language: lang)
2622
+ end
2623
+
2624
+ # (rule _RDFLiteral_3 (seq '^^' iri))
2625
+ production(:_RDFLiteral_3) do |value|
2626
+ value.last[:iri]
2627
+ end
2628
+
2629
+ # BooleanLiteral ::= 'true' | 'false'
2630
+ start_production(:BooleanLiteral, insensitive_strings: false)
2631
+ production(:BooleanLiteral) do |value|
2632
+ RDF::Literal::Boolean.new(value.downcase)
2633
+ end
2634
+
2635
+ # PrefixedName::= PNAME_LN | PNAME_NS
2636
+ production(:PrefixedName) do |value|
2637
+ # PNAME_NS is just the symbol, PNAME_LN is a resolved IRI
2638
+ value.is_a?(Symbol) ? self.prefix(value) : value
2639
+ end
2640
+
2641
+ ##
2642
+ # Initializes a new parser instance.
2643
+ #
2644
+ # @param [String, IO, StringIO, #to_s] input
2645
+ # @param [Hash{Symbol => Object}] options
2646
+ # @option options [Boolean] :all_vars (false)
2647
+ # If `true`, emits on empty `project` operator when parsing `SELECT *`, which will emit all in-scope variables, rather than just those used in solutions.
2648
+ # In the next minor release, the default for this option will change to `true`.
2649
+ # @option options [#to_s] :anon_base ("b0")
2650
+ # Basis for generating anonymous Nodes
2651
+ # @option options [#to_s] :base_uri (nil)
2652
+ # the base URI to use when resolving relative URIs (for acessing intermediate parser productions)
2653
+ # @option options [Logger, #write, #<<] :logger
2654
+ # Record error/info/debug output
2655
+ # @option options [Hash] :prefixes (Hash.new)
2656
+ # the prefix mappings to use (for acessing intermediate parser productions)
2657
+ # @option options [Boolean] :resolve_iris (false)
2658
+ # Resolve prefix and relative IRIs, otherwise, when serializing the parsed SSE
2659
+ # as S-Expressions, use the original prefixed and relative URIs along with `base` and `prefix`
2660
+ # definitions.
2661
+ # @option options [Boolean] :validate (false)
2662
+ # whether to validate the parsed statements and values
2663
+ # @yield [parser] `self`
2664
+ # @yieldparam [SPARQL::Grammar::Parser] parser
2665
+ # @yieldreturn [void] ignored
2666
+ # @return [SPARQL::Grammar::Parser]
2667
+ def initialize(input = nil, **options, &block)
2668
+ @input = case input
2669
+ when IO, StringIO then EBNF::Unescape.unescape_codepoints(input.read)
2670
+ else EBNF::Unescape.unescape_codepoints(input.to_s)
2671
+ end
2672
+ @input.encode!(Encoding::UTF_8) if @input.respond_to?(:encode!)
2673
+ @options = {anon_base: "b0", validate: false}.merge(options)
2674
+
2675
+ debug("base IRI") {base_uri.inspect}
2676
+ debug("validate") {validate?.inspect}
2677
+
2678
+ @vars = {}
2679
+ @nd_var_gen = "0"
2680
+
2681
+ if block_given?
2682
+ case block.arity
2683
+ when 0 then instance_eval(&block)
2684
+ else block.call(self)
2685
+ end
2686
+ end
2687
+ end
2688
+
2689
+ ##
2690
+ # Returns `true` if the input string is syntactically valid.
2691
+ #
2692
+ # @return [Boolean]
2693
+ def valid?
2694
+ parse
2695
+ true
2696
+ rescue Error
2697
+ false
2698
+ end
2699
+
2700
+ # @return [String]
2701
+ def to_sxp_bin
2702
+ @result
2703
+ end
2704
+
2705
+ def to_s
2706
+ @result.to_sxp
2707
+ end
2708
+
2709
+ alias_method :peg_parse, :parse
2710
+
2711
+ # Parse query
2712
+ #
2713
+ # The result is a SPARQL Algebra S-List. Productions return an array such as the following:
2714
+ #
2715
+ # (prefix ((: <http://example/>))
2716
+ # (union
2717
+ # (bgp (triple ?s ?p ?o))
2718
+ # (graph ?g
2719
+ # (bgp (triple ?s ?p ?o)))))
2720
+ #
2721
+ # @param [Symbol, #to_s] prod The starting production for the parser.
2722
+ # It may be a URI from the grammar, or a symbol representing the local_name portion of the grammar URI.
2723
+ # @return [RDF::Queryable]
2724
+ # @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
2725
+ # @see https://axel.deri.ie/sparqltutorial/ESWC2007_SPARQL_Tutorial_unit2b.pdf
2726
+ def parse(prod = :QueryUnit)
2727
+ res = peg_parse(@input,
2728
+ start: prod.to_sym,
2729
+ rules: SPARQL::Grammar::Meta::RULES,
2730
+ whitespace: WS,
2731
+ insensitive_strings: :upper,
2732
+ **@options
2733
+ )
2734
+
2735
+ # The last thing on the @prod_data stack is the result
2736
+ @result = case
2737
+ when !res.is_a?(Hash)
2738
+ res
2739
+ when res.empty?
2740
+ nil
2741
+ when res[:query]
2742
+ res[:query]
2743
+ when res[:update]
2744
+ res[:update]
2745
+ else
2746
+ key = res.keys.first
2747
+ value = res[key]
2748
+ value = [value] unless value.is_a?(Array)
2749
+ value.unshift(key)
2750
+ end
2751
+
2752
+ # Validate resulting expression
2753
+ @result.validate! if @result && validate?
2754
+ @result
2755
+ end
2756
+
2757
+ private
2758
+ ##
2759
+ # Returns the URI prefixes currently defined for this parser.
2760
+ #
2761
+ # @example
2762
+ # prefixes[:dc] #=> RDF::URI('http://purl.org/dc/terms/')
2763
+ #
2764
+ # @return [Hash{Symbol => RDF::URI}]
2765
+ # @since 0.3.0
2766
+ def prefixes
2767
+ @options[:prefixes] ||= {}
2768
+ end
2769
+
2770
+ ##
2771
+ # Defines the given URI prefixes for this parser.
2772
+ #
2773
+ # @example
2774
+ # prefixes = {
2775
+ # dc: RDF::URI('http://purl.org/dc/terms/'),
2776
+ # }
2777
+ #
2778
+ # @param [Hash{Symbol => RDF::URI}] prefixes
2779
+ # @return [Hash{Symbol => RDF::URI}]
2780
+ # @since 0.3.0
2781
+ def prefixes=(prefixes)
2782
+ @options[:prefixes] = prefixes
2783
+ end
2784
+
2785
+ ##
2786
+ # Defines the given named URI prefix for this parser.
2787
+ #
2788
+ # @example Defining a URI prefix
2789
+ # prefix :dc, RDF::URI('http://purl.org/dc/terms/')
2790
+ #
2791
+ # @example Returning a URI prefix
2792
+ # prefix(:dc) #=> RDF::URI('http://purl.org/dc/terms/')
2793
+ #
2794
+ # @overload prefix(name, uri)
2795
+ # @param [Symbol, #to_s] name
2796
+ # @param [RDF::URI, #to_s] uri
2797
+ #
2798
+ # @overload prefix(name)
2799
+ # @param [Symbol, #to_s] name
2800
+ #
2801
+ # @return [RDF::URI]
2802
+ def prefix(name, iri = nil)
2803
+ name = name.to_s.empty? ? nil : (name.respond_to?(:to_sym) ? name.to_sym : name.to_s.to_sym)
2804
+ iri.nil? ? prefixes[name] : prefixes[name] = iri
2805
+ end
2806
+
2807
+ ##
2808
+ # Returns the Base URI defined for the parser,
2809
+ # as specified or when parsing a BASE prologue element.
2810
+ #
2811
+ # @example
2812
+ # base #=> RDF::URI('http://example.com/')
2813
+ #
2814
+ # @return [HRDF::URI]
2815
+ def base_uri
2816
+ RDF::URI(@options[:base_uri])
2817
+ end
2818
+
2819
+ ##
2820
+ # Set the Base URI to use for this parser.
2821
+ #
2822
+ # @param [RDF::URI, #to_s] iri
2823
+ #
2824
+ # @example
2825
+ # base_uri = RDF::URI('http://purl.org/dc/terms/')
2826
+ #
2827
+ # @return [RDF::URI]
2828
+ def base_uri=(iri)
2829
+ @options[:base_uri] = RDF::URI(iri)
2830
+ end
2831
+
2832
+ ##
2833
+ # Returns `true` if parsed statements and values should be validated.
2834
+ #
2835
+ # @return [Boolean] `true` or `false`
2836
+ # @since 0.3.0
2837
+ def resolve_iris?
2838
+ @options[:resolve_iris]
2839
+ end
2840
+
2841
+ ##
2842
+ # Returns `true` when resolving IRIs, otherwise BASE and PREFIX are retained in the output algebra.
2843
+ #
2844
+ # @return [Boolean] `true` or `false`
2845
+ # @since 1.0.3
2846
+ def validate?
2847
+ @options[:validate]
2848
+ end
2849
+
2850
+ # Used for generating BNode labels
2851
+ attr_accessor :nd_var_gen
2852
+
2853
+ # Generate BNodes, not non-distinguished variables
2854
+ # @param [Boolean] value
2855
+ # @return [void]
2856
+ def gen_bnodes(value = true)
2857
+ @nd_var_gen = value ? false : "0"
2858
+ end
2859
+
2860
+ # Clear cached BNodes
2861
+ # @return [void]
2862
+ def clear_bnode_cache
2863
+ @bnode_cache = {}
2864
+ end
2865
+
2866
+ # Freeze BNodes, which allows us to detect if they're re-used
2867
+ # @return [void]
2868
+ def freeze_bnodes
2869
+ @bnode_cache ||= {}
2870
+ @bnode_cache.each_value(&:freeze)
2871
+ end
2872
+
2873
+ # Generate a BNode identifier
2874
+ def bnode(id = nil)
2875
+ if @nd_var_gen
2876
+ # Use non-distinguished variables within patterns
2877
+ variable(id, false)
2878
+ else
2879
+ unless id
2880
+ id = @options[:anon_base]
2881
+ @options[:anon_base] = @options[:anon_base].succ
2882
+ end
2883
+ @bnode_cache ||= {}
2884
+ raise Error, "Illegal attempt to reuse a BNode" if @bnode_cache[id] && @bnode_cache[id].frozen?
2885
+ @bnode_cache[id] ||= RDF::Node.new(id)
2886
+ end
2887
+ end
2888
+
2889
+ ##
2890
+ # Return variable allocated to an ID.
2891
+ # If no ID is provided, a new variable
2892
+ # is allocated. Otherwise, any previous assignment will be used.
2893
+ #
2894
+ # The variable has a #distinguished? method applied depending on if this
2895
+ # is a disinguished or non-distinguished variable. Non-distinguished
2896
+ # variables are effectively the same as BNodes.
2897
+ # @return [RDF::Query::Variable]
2898
+ def variable(id, distinguished = true)
2899
+ id = nil if id.to_s.empty?
2900
+
2901
+ if id
2902
+ @vars[id] ||= begin
2903
+ RDF::Query::Variable.new(id, distinguished: distinguished)
2904
+ end
2905
+ else
2906
+ unless distinguished
2907
+ # Allocate a non-distinguished variable identifier
2908
+ id = @nd_var_gen
2909
+ @nd_var_gen = id.succ
2910
+ end
2911
+ RDF::Query::Variable.new(id, distinguished: distinguished)
2912
+ end
2913
+ end
2914
+
2915
+ # Create URIs
2916
+ def iri(value)
2917
+ # If we have a base URI, use that when constructing a new URI
2918
+ value = RDF::URI(value)
2919
+ if base_uri && value.relative?
2920
+ base_uri.join(value)
2921
+ else
2922
+ value
2923
+ end
2924
+ end
2925
+
2926
+ def ns(prefix, suffix)
2927
+ base = prefix(prefix).to_s
2928
+ suffix = suffix.to_s.gsub(PN_LOCAL_ESC) {|esc| esc[1]} if
2929
+ suffix.to_s.match?(PN_LOCAL_ESC)
2930
+ suffix = suffix.to_s.sub(/^\#/, "") if base.index("#")
2931
+ debug {"ns(#{prefix.inspect}): base: '#{base}', suffix: '#{suffix}'"}
2932
+ iri(base + suffix.to_s)
2933
+ end
2934
+
2935
+ # Create a literal
2936
+ def literal(value, **options)
2937
+ options = options.dup
2938
+ # Internal representation is to not use xsd:string, although it could arguably go the other way.
2939
+ options.delete(:datatype) if options[:datatype] == RDF::XSD.string
2940
+ debug("literal") do
2941
+ "value: #{value.inspect}, " +
2942
+ "options: #{options.inspect}, " +
2943
+ "validate: #{validate?.inspect}, "
2944
+ end
2945
+ RDF::Literal.new(value, validate: validate?, **options)
2946
+ end
2947
+
2948
+ # Take collection of objects and create RDF Collection using rdf:first, rdf:rest and rdf:nil
2949
+ # @param [Hash] data Production Data
2950
+ # @return [Array] list of patterns
2951
+ def expand_collection(first, values)
2952
+ # Add any triples generated from deeper productions
2953
+ patterns = values.map {|v| v[:pattern]}.flatten.compact
2954
+
2955
+ # Create list items for each element in data[:GraphNode]
2956
+ list = values.map {|v| v[:object]}.compact
2957
+ last = list.pop
2958
+
2959
+ list.each do |r|
2960
+ patterns << add_pattern(:Collection, subject: first, predicate: RDF["first"], object: r)
2961
+ rest = bnode()
2962
+ patterns << add_pattern(:Collection, subject: first, predicate: RDF["rest"], object: rest)
2963
+ first = rest
2964
+ end
2965
+
2966
+ if last
2967
+ patterns << add_pattern(:Collection, subject: first, predicate: RDF["first"], object: last)
2968
+ end
2969
+ patterns << add_pattern(:Collection, subject: first, predicate: RDF["rest"], object: RDF["nil"])
2970
+ patterns
2971
+ end
2972
+
2973
+ # add a pattern
2974
+ #
2975
+ # @param [String] production Production generating pattern
2976
+ # @param [Boolean] tripleTerm For Triple Term
2977
+ # @param [Hash{Symbol => Object}] options
2978
+ def add_pattern(production, tripleTerm: false, **options)
2979
+ progress(production, "[:pattern, #{options[:subject]}, #{options[:predicate]}, #{options[:object]}]")
2980
+ triple = {}
2981
+ triple[:tripleTerm] = true if tripleTerm
2982
+ options.each_pair do |r, v|
2983
+ if v.is_a?(Array) && v.flatten.length == 1
2984
+ v = v.flatten.first
2985
+ end
2986
+ if validate? && !v.is_a?(RDF::Term)
2987
+ error("add_pattern", "Expected #{r} to be a resource, but it was #{v.inspect}",
2988
+ production: production)
2989
+ end
2990
+ triple[r] = v
2991
+ end
2992
+ RDF::Query::Pattern.new(triple)
2993
+ end
2994
+
2995
+ ##
2996
+ # Merge query modifiers, datasets, and projections
2997
+ #
2998
+ # This includes tranforming aggregates if also used with a GROUP BY
2999
+ #
3000
+ # @see http://www.w3.org/TR/sparql11-query/#convertGroupAggSelectExpressions
3001
+ def merge_modifiers(data)
3002
+ debug("merge modifiers") {data.inspect}
3003
+ query = data[:query] || SPARQL::Algebra::Operator::BGP.new
3004
+
3005
+ vars = Array(data[:Var])
3006
+ order = Array(data[:order])
3007
+ extensions = data[:extend] || []
3008
+ having = data[:having] || []
3009
+ values = data[:values] || []
3010
+
3011
+ # extension variables must not appear in projected variables.
3012
+ # Add them to the projection otherwise
3013
+ extensions.each do |(var, _)|
3014
+ raise Error, "Extension variable #{var} also in SELECT" if vars.map(&:to_s).include?(var.to_s)
3015
+ vars << var
3016
+ end
3017
+
3018
+ # If any extension contains an aggregate, and there is now group, implicitly group by 1
3019
+ if !data[:group] &&
3020
+ extensions.any? {|(_, function)| function.aggregate?} ||
3021
+ having.any? {|c| c.aggregate? }
3022
+ debug {"Implicit group"}
3023
+ data[:group] = []
3024
+ end
3025
+
3026
+ # Add datasets and modifiers in order
3027
+ if data[:group]
3028
+ group_vars = data[:group]
3029
+
3030
+ # For creating temporary variables
3031
+ agg = 0
3032
+
3033
+ # Find aggregated varirables in extensions
3034
+ aggregates = []
3035
+ aggregated_vars = extensions.map do |(var, function)|
3036
+ var if function.aggregate?
3037
+ end.compact
3038
+
3039
+ # Common function for replacing aggregates with temporary variables,
3040
+ # as defined in http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#convertGroupAggSelectExpressions
3041
+ aggregate_expression = lambda do |expr|
3042
+ # Replace unaggregated variables in expr
3043
+ # - For each unaggregated variable V in X
3044
+ expr.replace_vars! do |v|
3045
+ aggregated_vars.include?(v) ? v : SPARQL::Algebra::Expression[:sample, v]
3046
+ end
3047
+
3048
+ # Replace aggregates in expr as above
3049
+ expr.replace_aggregate! do |function|
3050
+ if avf = aggregates.detect {|(_, f)| f.equal?(function)}
3051
+ avf.first
3052
+ else
3053
+ # Allocate a temporary variable for this function, and retain the mapping for outside the group
3054
+ av = RDF::Query::Variable.new(".#{agg}", distinguished: false)
3055
+ agg += 1
3056
+ aggregates << [av, function]
3057
+ av
3058
+ end
3059
+ end
3060
+ end
3061
+
3062
+ # If there are extensions, they are aggregated if necessary and bound
3063
+ # to temporary variables
3064
+ extensions.map! do |(var, expr)|
3065
+ [var, aggregate_expression.call(expr)]
3066
+ end
3067
+
3068
+ # Having clauses
3069
+ having.map! do |expr|
3070
+ aggregate_expression.call(expr)
3071
+ end
3072
+
3073
+ query = if aggregates.empty?
3074
+ SPARQL::Algebra::Expression[:group, group_vars, query]
3075
+ else
3076
+ SPARQL::Algebra::Expression[:group, group_vars, aggregates, query]
3077
+ end
3078
+ end
3079
+
3080
+ query = SPARQL::Algebra::Expression[:join, query, values] unless values.empty?
3081
+
3082
+ query = SPARQL::Algebra::Expression[:extend, extensions, query] unless extensions.empty?
3083
+
3084
+ query = SPARQL::Algebra::Expression[:filter, *having, query] unless having.empty?
3085
+
3086
+ query = SPARQL::Algebra::Expression[:order, data[:order], query] unless order.empty?
3087
+
3088
+ # If SELECT * was used, emit a projection with empty variables, vs no projection at all. Only if :all_vars is true
3089
+ query = if vars == %w(*)
3090
+ options[:all_vars] ? SPARQL::Algebra::Expression[:project, [], query] : query
3091
+ elsif !vars.empty?
3092
+ SPARQL::Algebra::Expression[:project, vars, query]
3093
+ else
3094
+ query
3095
+ end
3096
+
3097
+ query = SPARQL::Algebra::Expression[data[:DISTINCT_REDUCED], query] if data[:DISTINCT_REDUCED]
3098
+
3099
+ query = SPARQL::Algebra::Expression[:slice, data[:slice][0], data[:slice][1], query] if data[:slice]
3100
+
3101
+ query = SPARQL::Algebra::Expression[:dataset, data[:dataset], query] if data[:dataset] && !data[:dataset].empty?
3102
+
3103
+ query
3104
+ end
3105
+
3106
+ # Add joined expressions in for prod1 (op prod2)* to form (op (op 1 2) 3)
3107
+ def add_operator_expressions(lhs, *exprs)
3108
+ # Iterate through expression to create binary operations
3109
+ exprs.each do |op, rhs|
3110
+ lhs = SPARQL::Algebra::Expression.for(op, lhs, rhs)
3111
+ end
3112
+ lhs
3113
+ end
3114
+ end # class Parser
3115
+ end # module SPARQL::Grammar