GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

ARC2_TurtleParser   D
last analyzed

Complexity

Total Complexity 256

Size/Duplication

Total Lines 873
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3
Metric Value
wmc 256
lcom 1
cbo 3
dl 0
loc 873
rs 4.4444

43 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A ARC2_TurtleParser() 0 3 1
A createBnodeID() 0 4 1
A getTriples() 0 3 1
A countTriples() 0 3 1
A getUnparsedCode() 0 3 1
F xTriplesBlock() 0 129 34
F xBlankNodePropertyList() 0 80 20
A xNumericLiteral() 0 13 4
A xDOUBLE() 0 12 4
A xPN_CHARS_U() 0 9 4
A xPN_CHARS() 0 9 4
A __init() 0 10 1
A x() 0 8 2
A addT() 0 14 3
A setDefaultPrefixes() 0 11 3
F parse() 0 69 20
B xPrologue() 0 14 6
B xBaseDecl() 0 11 5
B xPrefixDecl() 0 15 7
C xCollection() 0 42 12
B xVarOrTerm() 0 9 5
B xVar() 0 11 5
B xGraphTerm() 0 21 5
B xRDFLiteral() 0 14 9
A xBooleanLiteral() 0 6 2
C xString() 0 29 7
B xIRIref() 0 9 5
B xPrefixedName() 0 9 6
B xBlankNode() 0 9 5
B xIRI_REF() 0 13 6
A xPNAME_NS() 0 5 3
B xPNAME_LN() 0 11 7
A xLANGTAG() 0 6 3
A xINTEGER() 0 6 2
A xDECIMAL() 0 9 3
A xNIL() 0 6 2
A xPN_CHARS_BASE() 0 6 2
C xVARNAME() 0 22 7
C xPN_PREFIX() 0 23 8
C xPN_LOCAL() 0 33 13
B unescapeNtripleUTF() 0 18 10
B xPlaceholder() 0 13 6

How to fix   Complexity   

Complex Class

Complex classes like ARC2_TurtleParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ARC2_TurtleParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * ARC2 SPARQL-enhanced Turtle Parser
4
 *
5
 * @author Benjamin Nowack
6
 * @license <http://arc.semsol.org/license>
7
 * @homepage <http://arc.semsol.org/>
8
 * @package ARC2
9
 * @version 2010-04-11
10
*/
11
12
ARC2::inc('RDFParser');
13
14
class ARC2_TurtleParser extends ARC2_RDFParser {
15
16
  function __construct($a = '', &$caller) {
17
    parent::__construct($a, $caller);
18
  }
19
  
20
  function ARC2_TurtleParser($a = '', &$caller) {
21
    $this->__construct($a, $caller);
22
  }
23
24
  function __init() {/* reader */
25
    parent::__init();
26
    $this->state = 0;
27
    $this->xml = 'http://www.w3.org/XML/1998/namespace';
28
    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
29
    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
30
    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd');
31
    $this->unparsed_code = '';
32
    $this->max_parsing_loops = $this->v('turtle_max_parsing_loops', 500, $this->a);
33
  }
34
  
35
  /*  */
36
  
37
  function x($re, $v, $options = 'si') {
38
    $v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
39
    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
40
      $v = $m[2];
41
    }
42
    return ARC2::x($re, $v, $options);
43
    //$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
44
  }
45
46
  function createBnodeID(){
47
    $this->bnode_id++;
48
    return '_:' . $this->bnode_prefix . $this->bnode_id;
49
  }
50
51
  /*  */
52
  
53
  function addT($t) {
54
    if ($this->skip_dupes) {
55
      $h = md5(serialize($t));
56
      if (!isset($this->added_triples[$h])) {
57
        $this->triples[$this->t_count] = $t;
58
        $this->t_count++;
59
        $this->added_triples[$h] = true;
60
      }
61
    }
62
    else {
63
      $this->triples[$this->t_count] = $t;
64
      $this->t_count++;
65
    }
66
  }
67
68
  /*  */
69
70
  function getTriples() {
71
    return $this->v('triples', array());
72
  }
73
  
74
  function countTriples() {
75
    return $this->t_count;
76
  }
77
  
78
  /*  */
79
  
80
  function getUnparsedCode() {
81
    return $this->v('unparsed_code', '');
82
  }
83
  
84
  /*  */
85
  
86
  function setDefaultPrefixes() {
87
    $this->prefixes = array(
88
      'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
89
      'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
90
      'owl:' => 'http://www.w3.org/2002/07/owl#',
91
      'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
92
    );
93
    if ($ns = $this->v('ns', array(), $this->a)) {
94
      foreach ($ns as $p => $u) $this->prefixes[$p . ':'] = $u;
95
    }
96
  }
97
  
98
99
  function parse($path, $data = '', $iso_fallback = false) {
100
    $this->setDefaultPrefixes();
101
    /* reader */
102
    if (!$this->v('reader')) {
103
      ARC2::inc('Reader');
104
      $this->reader = & new ARC2_Reader($this->a, $this);
105
    }
106
    $this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
107
    $this->reader->activate($path, $data);
108
    $this->base = $this->v1('base', $this->reader->base, $this->a);
109
    $this->r = array('vars' => array());
110
    /* parse */
111
    $buffer = '';
112
    $more_triples = array();
113
    $sub_v = '';
114
    $sub_v2 = '';
115
    $loops = 0;
116
    $prologue_done = 0;
117
    while ($d = $this->reader->readStream(0)) {
118
      $buffer .= $d;
119
      $sub_v = $buffer;
120
      do {
121
        $proceed = 0;
122
        if (!$prologue_done) {
123
          $proceed = 1;
124
          if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
125
            $loops = 0;
126
            $sub_v .= $this->reader->readStream(0, 128);
127
            /* we might have missed the final DOT in the previous prologue loop */
128
            if ($sub_r = $this->x('\.', $sub_v)) $sub_v = $sub_r[1];
129
            if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
130
              $proceed = 0;
131
            }
132
          }
133
          else {
134
            $prologue_done = 1;
135
          }
136
        }
137
        if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
138
          $proceed = 1;
139
          $loops = 0;
140
          foreach ($sub_r as $t) {
141
            $this->addT($t);
142
          }
143
        }
144
      } while ($proceed);
145
      $loops++;
146
      $buffer = $sub_v;
147
      if ($loops > $this->max_parsing_loops) {/* most probably a parser or code bug, might also be a huge object value, though */
148
        $this->addError('too many loops: ' . $loops . '. Could not parse "' . substr($buffer, 0, 200) . '..."');
149
        break;
150
      }
151
    }
152
    foreach ($more_triples as $t) {
153
      $this->addT($t);
154
    }
155
    $sub_v = count($more_triples) ? $sub_v2 : $sub_v;
156
    $buffer = $sub_v;
157
    $this->unparsed_code = $buffer;
158
    $this->reader->closeStream();
159
    unset($this->reader);
160
    /* remove trailing comments */
161
    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
162
    if ($this->unparsed_code && !$this->getErrors()) {
163
      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
164
      if (trim($rest)) $this->addError('Could not parse "' . $rest . '"');
165
    }
166
    return $this->done();
167
  }
168
169
  function xPrologue($v) {
170
    $r = 0;
171
    if (!$this->t_count) {
172
      if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
173
        $this->base = $sub_r;
174
        $r = 1;
175
      }
176
      while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
177
        $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
178
        $r = 1;
179
      }
180
    }
181
    return array($r, $v);
182
  }
183
  
184
  /* 3 */
185
186
  function xBaseDecl($v) {
187
    if ($r = $this->x("\@?base\s+", $v)) {
188
      if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
189
        if ($sub_r = $this->x('\.', $sub_v)) {
190
          $sub_v = $sub_r[1];
191
        }
192
        return array($r, $sub_v);
193
      }
194
    }
195
    return array(0, $v);
196
  }
197
  
198
  /* 4 */
199
  
200
  function xPrefixDecl($v) {
201
    if ($r = $this->x("\@?prefix\s+", $v)) {
202
      if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
203
        $prefix = $r;
204
        if((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
205
          $uri = $this->calcURI($r, $this->base);
206
          if ($sub_r = $this->x('\.', $sub_v)) {
207
            $sub_v = $sub_r[1];
208
          }
209
          return array(array('prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri), $sub_v);
210
        }
211
      }
212
    }
213
    return array(0, $v);
214
  }
215
216
  /* 21.., 32.. */
217
  
218
  function xTriplesBlock($v) {
219
    $pre_r = array();
220
    $r = array();
221
    $state = 1;
222
    $sub_v = $v;
223
    $buffer = $sub_v;
224
    do {
225
      $proceed = 0;
226
      if ($state == 1) {/* expecting subject */
227
        $t = array('type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
228
        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
229
          $t['s'] = $sub_r['value'];
230
          $t['s_type'] = $sub_r['type'];
231
          $state = 2;
232
          $proceed = 1;
233
          if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
234
            if ($t['s_type'] == 'placeholder') {
235
              $state = 4;
236
            }
237
            else {
238
              $this->addError('"' . $sub_r[1]. '" after subject found.');
239
            }
240
          }
241
        }
242
        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
243
          $t['s'] = $sub_r['id'];
244
          $t['s_type'] = $sub_r['type'];
245
          $pre_r = array_merge($pre_r, $sub_r['triples']);
246
          $state = 2;
247
          $proceed = 1;
248
          if ($sub_r = $this->x('\.', $sub_v)) {
249
            $this->addError('DOT after subject found.');
250
          }
251
        }
252
        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
253
          $t['s'] = $sub_r['id'];
254
          $t['s_type'] = $sub_r['type'];
255
          $pre_r = array_merge($pre_r, $sub_r['triples']);
256
          $state = 2;
257
          $proceed = 1;
258
        }
259
        elseif ($sub_r = $this->x('\.', $sub_v)) {
260
          $this->addError('Subject expected, DOT found.' . $sub_v);
261
        }
262
      }
263
      if ($state == 2) {/* expecting predicate */
264
        if ($sub_r = $this->x('a\s+', $sub_v)) {
265
          $sub_v = $sub_r[1];
266
          $t['p'] = $this->rdf . 'type';
267
          $t['p_type'] = 'uri';
268
          $state = 3;
269
          $proceed = 1;
270
        }
271
        elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
272
          if ($sub_r['type'] == 'bnode') {
273
            $this->addError('Blank node used as triple predicate');
274
          }
275
          $t['p'] = $sub_r['value'];
276
          $t['p_type'] = $sub_r['type'];
277
          $state = 3;
278
          $proceed = 1;
279
        }
280
        elseif ($sub_r = $this->x('\.', $sub_v)) {
281
          $state = 4;          
282
        }
283
        elseif ($sub_r = $this->x('\}', $sub_v)) {
284
          $buffer = $sub_v;
285
          $r = array_merge($r, $pre_r);
286
          $pre_r = array();
287
          $proceed = 0;
288
        }
289
      }
290
      if ($state == 3) {/* expecting object */
291
        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
292
          $t['o'] = $sub_r['value'];
293
          $t['o_type'] = $sub_r['type'];
294
          $t['o_lang'] = $this->v('lang', '', $sub_r);
295
          $t['o_datatype'] = $this->v('datatype', '', $sub_r);
296
          $pre_r[] = $t;
297
          $state = 4;
298
          $proceed = 1;
299
        }
300
        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
301
          $t['o'] = $sub_r['id'];
302
          $t['o_type'] = $sub_r['type'];
303
          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
304
          $state = 4;
305
          $proceed = 1;
306
        }
307
        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
308
          $t['o'] = $sub_r['id'];
309
          $t['o_type'] = $sub_r['type'];
310
          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
311
          $state = 4;
312
          $proceed = 1;
313
        }
314
      }
315
      if ($state == 4) {/* expecting . or ; or , or } */
316
        if ($sub_r = $this->x('\.', $sub_v)) {
317
          $sub_v = $sub_r[1];
318
          $buffer = $sub_v;
319
          $r = array_merge($r, $pre_r);
320
          $pre_r = array();
321
          $state = 1;
322
          $proceed = 1;
323
        }
324
        elseif ($sub_r = $this->x('\;', $sub_v)) {
325
          $sub_v = $sub_r[1];
326
          $state = 2;
327
          $proceed = 1;
328
        }
329
        elseif ($sub_r = $this->x('\,', $sub_v)) {
330
          $sub_v = $sub_r[1];
331
          $state = 3;
332
          $proceed = 1;
333
          if ($sub_r = $this->x('\}', $sub_v)) {
334
            $this->addError('Object expected, } found.');
335
          }
336
        }
337
        if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
338
          $buffer = $sub_v;
339
          $r = array_merge($r, $pre_r);
340
          $pre_r = array();
341
          $proceed = 0;
342
        }
343
      }
344
    } while ($proceed);
345
    return count($r) ? array($r, $buffer, $pre_r, $sub_v) : array(0, $buffer, $pre_r, $sub_v);
346
  }
347
  
348
  /* 39.. */
349
  
350
  function xBlankNodePropertyList($v) {
351
    if ($sub_r = $this->x('\[', $v)) {
352
      $sub_v = $sub_r[1];
353
      $s = $this->createBnodeID();
354
      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
355
      $t = array('type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
356
      $state = 2;
357
      $closed = 0;
358
      do {
359
        $proceed = 0;
360
        if ($state == 2) {/* expecting predicate */
361
          if ($sub_r = $this->x('a\s+', $sub_v)) {
362
            $sub_v = $sub_r[1];
363
            $t['p'] = $this->rdf . 'type';
364
            $t['p_type'] = 'uri';
365
            $state = 3;
366
            $proceed = 1;
367
          }
368
          elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
369
            $t['p'] = $sub_r['value'];
370
            $t['p_type'] = $sub_r['type'];
371
            $state = 3;
372
            $proceed = 1;
373
          }
374
        }
375
        if ($state == 3) {/* expecting object */
376
          if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
377
            $t['o'] = $sub_r['value'];
378
            $t['o_type'] = $sub_r['type'];
379
            $t['o_lang'] = $this->v('lang', '', $sub_r);
380
            $t['o_datatype'] = $this->v('datatype', '', $sub_r);
381
            $r['triples'][] = $t;
382
            $state = 4;
383
            $proceed = 1;
384
          }
385
          elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
386
            $t['o'] = $sub_r['id'];
387
            $t['o_type'] = $sub_r['type'];
388
            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
389
            $state = 4;
390
            $proceed = 1;
391
          }
392
          elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
393
            $t['o'] = $sub_r['id'];
394
            $t['o_type'] = $sub_r['type'];
395
            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
396
            $state = 4;
397
            $proceed = 1;
398
          }
399
        }
400
        if ($state == 4) {/* expecting . or ; or , or ] */
401
          if ($sub_r = $this->x('\.', $sub_v)) {
402
            $sub_v = $sub_r[1];
403
            $state = 1;
404
            $proceed = 1;
405
          }
406
          if ($sub_r = $this->x('\;', $sub_v)) {
407
            $sub_v = $sub_r[1];
408
            $state = 2;
409
            $proceed = 1;
410
          }
411
          if ($sub_r = $this->x('\,', $sub_v)) {
412
            $sub_v = $sub_r[1];
413
            $state = 3;
414
            $proceed = 1;
415
          }
416
          if ($sub_r = $this->x('\]', $sub_v)) {
417
            $sub_v = $sub_r[1];
418
            $proceed = 0;
419
            $closed = 1;
420
          }
421
        }
422
      } while ($proceed);
423
      if ($closed) {
424
        return array($r, $sub_v);
425
      }
426
      return array(0, $v);
427
    }
428
    return array(0, $v);
429
  }
430
  
431
  /* 40.. */
432
  
433
  function xCollection($v) {
434
    if ($sub_r = $this->x('\(', $v)) {
435
      $sub_v = $sub_r[1];
436
      $s = $this->createBnodeID();
437
      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
438
      $closed = 0;
439
      do {
440
        $proceed = 0;
441
        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
442
          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r));
443
          $proceed = 1;
444
        }
445
        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
446
          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
447
          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
448
          $proceed = 1;
449
        }
450
        elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
451
          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
452
          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
453
          $proceed = 1;
454
        }
455
        if ($proceed) {
456
          if ($sub_r = $this->x('\)', $sub_v)) {
457
            $sub_v = $sub_r[1];
458
            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $this->rdf . 'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => '');
459
            $closed = 1;
460
            $proceed = 0;
461
          }
462
          else {
463
            $next_s = $this->createBnodeID();
464
            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => '');
465
            $s = $next_s;
466
          }
467
        }
468
      } while ($proceed);
469
      if ($closed) {
470
        return array($r, $sub_v);
471
      }
472
    }
473
    return array (0, $v);
474
  }
475
  
476
  /* 42 */
477
  
478
  function xVarOrTerm($v) {
479
    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
480
      return array($sub_r, $sub_v);
481
    }
482
    elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
483
      return array($sub_r, $sub_v);
484
    }
485
    return array(0, $v);
486
  }
487
  
488
  /* 44, 74.., 75.. */
489
  
490
  function xVar($v) {
491
    if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
492
      if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
493
        if (!in_array($sub_r, $this->r['vars'])) {
494
          $this->r['vars'][] = $sub_r;
495
        }
496
        return array(array('value' => $sub_r, 'type' => 'var'), $sub_v . $r[3]);
497
      }
498
    }
499
    return array(0, $v);
500
  }
501
502
  /* 45 */
503
  
504
  function xGraphTerm($v) {
505
    foreach (array(
506
      'IRIref' => 'uri', 
507
      'RDFLiteral' => 'literal', 
508
      'NumericLiteral' => 'literal', 
509
      'BooleanLiteral' => 'literal', 
510
      'BlankNode' => 'bnode', 
511
      'NIL' => 'uri',
512
      'Placeholder' => 'placeholder'
513
    ) as $term => $type) {
514
      $m = 'x' . $term;
515
      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
516
        if (!is_array($sub_r)) {
517
          $sub_r = array('value' => $sub_r);
518
        }
519
        $sub_r['type'] = $this->v1('type', $type, $sub_r);
520
        return array($sub_r, $sub_v);
521
      }
522
    }
523
    return array(0, $v);
524
  }
525
526
  /* 60 */
527
  
528
  function xRDFLiteral($v) {
529
    if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
530
      $sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
531
      $r = $sub_r;
532
      if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
533
        $r['lang'] = $sub_r;
534
      }
535
      elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
536
        $r['datatype'] = $sub_r;
537
      }
538
      return array($r, $sub_v);
539
    }
540
    return array(0, $v);
541
  }
542
543
  /* 61.., 62.., 63.., 64.. */  
544
  
545
  function xNumericLiteral($v) {
546
    $sub_r = $this->x('(\-|\+)?', $v);
547
    $prefix = $sub_r[1];
548
    $sub_v = $sub_r[2];
549
    foreach (array('DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer') as $type => $xsd) {
550
      $m = 'x' . $type;
551
      if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && ($sub_r !== false)) {
552
        $r = array('value' => $prefix . $sub_r, 'type' => 'literal', 'datatype' => $this->xsd . $xsd);
553
        return array($r, $sub_v);
554
      }
555
    }
556
    return array(0, $v);
557
  }
558
  
559
  /* 65.. */
560
  
561
  function xBooleanLiteral($v) {
562
    if ($r = $this->x('(true|false)', $v)) {
563
      return array($r[1], $r[2]);
564
    }
565
    return array(0, $v);
566
  }
567
568
  /* 66.., 87.., 88.., 89.., 90.., 91.. */
569
  
570
  function xString($v) {/* largely simplified, may need some tweaks in following revisions */
571
    $sub_v = $v;
572
    if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) return array(0, $v);
573
    $delim = $m[1];
574
    $rest = $m[2];
575
    $sub_types = array("'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2');
576
    $sub_type = $sub_types[$delim];
577
    $pos = 0;
578
    $r = false;
579
    do {
580
      $proceed = 0;
581
      $delim_pos = strpos($rest, $delim, $pos);
582
      if ($delim_pos === false) break;
583
      $new_rest = substr($rest, $delim_pos + strlen($delim));
584
      $r = substr($rest, 0, $delim_pos);
585
      if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
586
        $rest = $new_rest;
587
      }
588
      else {
589
        $r = false;
590
        $pos = $delim_pos + 1;
591
        $proceed = 1;
592
      }
593
    } while ($proceed);
594
    if ($r !== false) {
595
      return array(array('value' => $this->toUTF8($r) , 'type' => 'literal', 'sub_type' => $sub_type), $rest);
596
    }
597
    return array(0, $v);
598
  }
599
  
600
  /* 67 */
601
  
602
  function xIRIref($v) {
603
    if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
604
      return array($this->calcURI($r, $this->base), $v);
605
    }
606
    elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
607
      return array($r, $v);
608
    }
609
    return array(0, $v);
610
  }
611
  
612
  /* 68 */
613
  
614
  function xPrefixedName($v) {
615
    if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
616
      return array($r, $v);
617
    }
618
    elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
619
      return isset($this->prefixes[$r]) ? array($this->prefixes[$r], $sub_v) : array(0, $v);
620
    }
621
    return array(0, $v);
622
  }
623
  
624
  /* 69.., 73.., 93, 94..  */
625
  
626
  function xBlankNode($v) {
627
    if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
628
      return array(array('type' => 'bnode', 'value' => '_:' . $r), $sub_v);
629
    }
630
    if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
631
      return array(array('type' => 'bnode', 'value' => $this->createBnodeID()), $r[1]);
632
    }
633
    return array(0, $v);
634
  }
635
636
  /* 70.. @@sync with SPARQLParser */
637
  
638
  function xIRI_REF($v) {
639
    //if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
640
    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
641
      return array($r[1], $r[2]);
642
    }
643
    elseif ($r = $this->x('\<\>', $v)) {
644
      return array(true, $r[1]);
645
    }
646
    elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
647
      return array($r[1] ? $r[1] : true, $r[2]);
648
    }
649
    return array(0, $v);
650
  }
651
  
652
  /* 71 */
653
  
654
  function xPNAME_NS($v) {
655
    list($r, $sub_v) = $this->xPN_PREFIX($v);
656
    $prefix = $r ? $r : '';
657
    return ($r = $this->x("\:", $sub_v)) ? array($prefix . ':', $r[1]) : array(0, $v);
658
  }
659
660
  /* 72 */
661
  
662
  function xPNAME_LN($v) {
663
    if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
664
      if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
665
        if (!isset($this->prefixes[$r])) {
666
          return array(0, $v);
667
        }
668
        return array($this->prefixes[$r] . $sub_r, $sub_v);
669
      }
670
    }
671
    return array(0, $v);
672
  }
673
  
674
  /* 76 */
675
  
676
  function xLANGTAG($v) {
677
    if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
678
      return array($r[1], $r[3]);
679
    }
680
    return array(0, $v);
681
  }
682
  
683
  /* 77.. */
684
  
685
  function xINTEGER($v) {
686
    if ($r = $this->x('([0-9]+)', $v)) {
687
      return array($r[1], $r[2]);
688
    }
689
    return array(false, $v);
690
  }
691
692
  /* 78.. */
693
694
  function xDECIMAL($v) {
695
    if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
696
      return array($r[1], $r[2]);
697
    }
698
    if ($r = $this->x('(\.[0-9]+)', $v)) {
699
      return array($r[1], $r[2]);
700
    }
701
    return array(false, $v);
702
  }
703
704
  /* 79.., 86.. */
705
706
  function xDOUBLE($v) {
707
    if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
708
      return array($r[1], $r[2]);
709
    }
710
    if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
711
      return array($r[1], $r[2]);
712
    }
713
    if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
714
      return array($r[1], $r[2]);
715
    }
716
    return array(false, $v);
717
  }
718
  
719
  /* 92 */
720
  
721
  function xNIL($v) {
722
    if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
723
      return array(array('type' => 'uri', 'value' => $this->rdf . 'nil'), $r[1]);
724
    }
725
    return array(0, $v);
726
  }
727
728
  /* 95.. */
729
  
730
  function xPN_CHARS_BASE($v) {
731
    if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
732
      return array($r[1], $r[2]);
733
    }
734
    return array(0, $v);
735
  }
736
737
  /* 96 */
738
  
739
  function xPN_CHARS_U($v) {
740
    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
741
      return array($r, $sub_v);
742
    }
743
    elseif ($r = $this->x("(_)", $v)) {
744
      return array($r[1], $r[2]);
745
    }
746
    return array(0, $v);
747
  }
748
749
  /* 97.. */
750
  
751
  function xVARNAME($v) {
752
    $r = '';
753
    do {
754
      $proceed = 0;
755
      if ($sub_r = $this->x('([0-9]+)', $v)) {
756
        $r .= $sub_r[1];
757
        $v = $sub_r[2];
758
        $proceed = 1;
759
      }
760
      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
761
        $r .= $sub_r;
762
        $v = $sub_v;
763
        $proceed = 1;
764
      }
765
      elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
766
        $r .= $sub_r[1];
767
        $v = $sub_r[2];
768
        $proceed = 1;
769
      }
770
    } while ($proceed);
771
    return array($r, $v);
772
  }
773
774
  /* 98.. */
775
  
776
  function xPN_CHARS($v) {
777
    if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
778
      return array($r, $sub_v);
779
    }
780
    elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
781
      return array($r[1], $r[2]);
782
    }
783
    return array(false, $v);
784
  }
785
786
  /* 99 */
787
  
788
  function xPN_PREFIX($v) {
789
    if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
790
      return array($sub_r[1], $sub_r[2]);/* @@testing */
791
    }
792
    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
793
      do {
794
        $proceed = 0;
795
        list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
796
        if ($sub_r !== false) {
797
          $r .= $sub_r;
798
          $proceed = 1;
799
        }
800
        elseif ($sub_r = $this->x("\.", $sub_v)) {
801
          $r .= '.';
802
          $sub_v = $sub_r[1];
803
          $proceed = 1;
804
        }
805
      } while ($proceed);
806
      list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
807
      $r .= $sub_r ? $sub_r : '';
808
    }
809
    return array($r, $sub_v);
810
  }
811
  
812
  /* 100 */
813
  
814
  function xPN_LOCAL($v) {
815
    if (($sub_r = $this->x("([^\s\(\)\{\}\[\]\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
816
      return array($sub_r[1], $sub_r[2]);/* @@testing */
817
    }
818
    $r = '';
819
    $sub_v = $v;
820
    do {
821
      $proceed = 0;
822
      if ($this->x('\s', $sub_v)) {
823
        return array($r, $sub_v);
824
      }
825
      if ($sub_r = $this->x('([0-9])', $sub_v)) {
826
        $r .= $sub_r[1];
827
        $sub_v = $sub_r[2];
828
        $proceed = 1;
829
      }
830
      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
831
        $r .= $sub_r;
832
        $proceed = 1;
833
      }
834
      elseif ($r) {
835
        if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^[\s\}]/s', $sub_r[2])) {
836
          $r .= $sub_r[1];
837
          $sub_v = $sub_r[2];
838
        }
839
        if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
840
          $r .= $sub_r;
841
          $proceed = 1;
842
        }
843
      }
844
    } while ($proceed);
845
    return array($r, $sub_v);
846
  }
847
  
848
  /*  */
849
  
850
  function unescapeNtripleUTF($v) {
851
    if (strpos($v, '\\') === false) return $v;
852
    $mappings = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'");
853
    foreach ($mappings as $in => $out) {
854
      $v = preg_replace('/\x5c([' . $in . '])/', $out, $v);
855
    }
856
    if (strpos(strtolower($v), '\u') === false) return $v;
857
    while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
858
      $no = hexdec($m[2]);
859
  		if ($no < 128) $char = chr($no);
860
      else if ($no < 2048) $char = chr(($no >> 6) + 192) . chr(($no & 63) + 128);
861
      else if ($no < 65536) $char = chr(($no >> 12) + 224) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
862
  		else if ($no < 2097152) $char = chr(($no >> 18) + 240) . chr((($no >> 12) & 63) + 128) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
863
      else $char= '';
864
      $v = str_replace('\\' . $m[1] . $m[2], $char, $v);
865
    }
866
    return $v;
867
  }
868
  
869
  /*  */
870
  
871
  function xPlaceholder($v) {
872
    //if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
873
    if ($r = $this->x('(\?|\$)', $v)) {
874
      if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && strpos(trim($r[2]), $m[1]) === 0) {
875
        $ph = substr($m[1], 1, -1);
876
        $rest = substr(trim($r[2]), strlen($m[1]));
877
        if (!isset($this->r['placeholders'])) $this->r['placeholders'] = array();
878
        if (!in_array($ph, $this->r['placeholders'])) $this->r['placeholders'][] = $ph;
879
        return array(array('value' => $ph, 'type' => 'placeholder'), $rest);
880
      }
881
    }
882
    return array(0, $v);
883
  }
884
  
885
  /*  */
886
}
887