Mercurial > hg > rr-repo
diff sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLParser.php @ 4:ce11bbd8f642
added modules
author | danieleb <danielebarchiesi@me.com> |
---|---|
date | Thu, 19 Sep 2013 10:38:44 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLParser.php Thu Sep 19 10:38:44 2013 +0100 @@ -0,0 +1,777 @@ +<?php +/** + * ARC2 SPARQL Parser + * + * @author Benjamin Nowack + * @license <http://arc.semsol.org/license> + * @homepage <http://arc.semsol.org/> + * @package ARC2 + * @version 2010-11-16 +*/ + +ARC2::inc('TurtleParser'); + +class ARC2_SPARQLParser extends ARC2_TurtleParser { + + function __construct($a, &$caller) { + parent::__construct($a, $caller); + } + + function __init() { + parent::__init(); + $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a); + $this->bnode_id = 0; + $this->bnode_pattern_index = array('patterns' => array(), 'bnodes' => array()); + } + + /* */ + + function parse($q, $src = '', $iso_fallback = 'ignore') { + $this->setDefaultPrefixes(); + $this->base = $src ? $this->calcBase($src) : ARC2::getRequestURI(); + $this->r = array( + 'base' => '', + 'vars' => array(), + 'prefixes' => array() + ); + $this->unparsed_code = $q; + list($r, $v) = $this->xQuery($q); + if ($r) { + $this->r['query'] = $r; + $this->unparsed_code = trim($v); + } + elseif (!$this->getErrors() && !$this->unparsed_code) { + $this->addError('Query not properly closed'); + } + $this->r['prefixes'] = $this->prefixes; + $this->r['base'] = $this->base; + /* remove trailing comments */ + while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2]; + if ($this->unparsed_code && !$this->getErrors()) { + $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30)); + $msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax error, probably an incomplete pattern'; + $this->addError($msg); + } + } + + function getQueryInfos() { + return $this->v('r', array()); + } + + /* 1 */ + + function xQuery($v) { + list($r, $v) = $this->xPrologue($v); + foreach (array('Select', 'Construct', 'Describe', 'Ask') as $type) { + $m = 'x' . $type . 'Query'; + if ((list($r, $v) = $this->$m($v)) && $r) { + return array($r, $v); + } + } + return array(0, $v); + } + + /* 2 */ + + function xPrologue($v) { + $r = 0; + if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) { + $this->base = $sub_r; + $r = 1; + } + while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) { + $this->prefixes[$sub_r['prefix']] = $sub_r['uri']; + $r = 1; + } + return array($r, $v); + } + + /* 5.. */ + + function xSelectQuery($v) { + if ($sub_r = $this->x('SELECT\s+', $v)) { + $r = array( + 'type' => 'select', + 'result_vars' => array(), + 'dataset' => array(), + ); + $all_vars = 0; + $sub_v = $sub_r[1]; + /* distinct, reduced */ + if ($sub_r = $this->x('(DISTINCT|REDUCED)\s+', $sub_v)) { + $r[strtolower($sub_r[1])] = 1; + $sub_v = $sub_r[2]; + } + /* result vars */ + if ($sub_r = $this->x('\*\s+', $sub_v)) { + $all_vars = 1; + $sub_v = $sub_r[1]; + } + else { + while ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) { + $r['result_vars'][] = $sub_r; + } + } + if (!$all_vars && !count($r['result_vars'])) { + $this->addError('No result bindings specified.'); + } + /* dataset */ + while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) { + $r['dataset'][] = $sub_r; + } + /* where */ + if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) { + $r['pattern'] = $sub_r; + } + else { + return array(0, $v); + } + /* solution modifier */ + if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) { + $r = array_merge($r, $sub_r); + } + /* all vars */ + if ($all_vars) { + foreach ($this->r['vars'] as $var) { + $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => ''); + } + if (!$r['result_vars']) { + $r['result_vars'][] = '*'; + } + } + return array($r, $sub_v); + } + return array(0, $v); + } + + function xResultVar($v) { + return $this->xVar($v); + } + + /* 6.. */ + + function xConstructQuery($v) { + if ($sub_r = $this->x('CONSTRUCT\s*', $v)) { + $r = array( + 'type' => 'construct', + 'dataset' => array(), + ); + $sub_v = $sub_r[1]; + /* construct template */ + if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) { + $r['construct_triples'] = $sub_r; + } + else { + $this->addError('Construct Template not found'); + return array(0, $v); + } + /* dataset */ + while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) { + $r['dataset'][] = $sub_r; + } + /* where */ + if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) { + $r['pattern'] = $sub_r; + } + else { + return array(0, $v); + } + /* solution modifier */ + if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) { + $r = array_merge($r, $sub_r); + } + return array($r, $sub_v); + } + return array(0, $v); + } + + /* 7.. */ + + function xDescribeQuery($v) { + if ($sub_r = $this->x('DESCRIBE\s+', $v)) { + $r = array( + 'type' => 'describe', + 'result_vars' => array(), + 'result_uris' => array(), + 'dataset' => array(), + ); + $sub_v = $sub_r[1]; + $all_vars = 0; + /* result vars/uris */ + if ($sub_r = $this->x('\*\s+', $sub_v)) { + $all_vars = 1; + $sub_v = $sub_r[1]; + } + else { + do { + $proceed = 0; + if ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) { + $r['result_vars'][] = $sub_r; + $proceed = 1; + } + if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) { + $r['result_uris'][] = $sub_r; + $proceed =1; + } + } while ($proceed); + } + if (!$all_vars && !count($r['result_vars']) && !count($r['result_uris'])) { + $this->addError('No result bindings specified.'); + } + /* dataset */ + while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) { + $r['dataset'][] = $sub_r; + } + /* where */ + if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) { + $r['pattern'] = $sub_r; + } + /* solution modifier */ + if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) { + $r = array_merge($r, $sub_r); + } + /* all vars */ + if ($all_vars) { + foreach ($this->r['vars'] as $var) { + $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => ''); + } + } + return array($r, $sub_v); + } + return array(0, $v); + } + + /* 8.. */ + + function xAskQuery($v) { + if ($sub_r = $this->x('ASK\s+', $v)) { + $r = array( + 'type' => 'ask', + 'dataset' => array(), + ); + $sub_v = $sub_r[1]; + /* dataset */ + while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) { + $r['dataset'][] = $sub_r; + } + /* where */ + if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) { + $r['pattern'] = $sub_r; + return array($r, $sub_v); + } + else { + $this->addError('Missing or invalid WHERE clause.'); + } + } + return array(0, $v); + } + + /* 9, 10, 11, 12 */ + + function xDatasetClause($v) { + if ($r = $this->x('FROM(\s+NAMED)?\s+', $v)) { + $named = $r[1] ? 1 : 0; + if ((list($r, $sub_v) = $this->xIRIref($r[2])) && $r) { + return array(array('graph' => $r, 'named' => $named), $sub_v); + } + } + return array(0, $v); + } + + /* 13 */ + + function xWhereClause($v) { + if ($r = $this->x('(WHERE)?', $v)) { + $v = $r[2]; + } + if ((list($r, $v) = $this->xGroupGraphPattern($v)) && $r) { + return array($r, $v); + } + return array(0, $v); + } + + /* 14, 15 */ + + function xSolutionModifier($v) { + $r = array(); + if ((list($sub_r, $sub_v) = $this->xOrderClause($v)) && $sub_r) { + $r['order_infos'] = $sub_r; + } + while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) { + $r = array_merge($r, $sub_r); + } + return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v); + } + + /* 18, 19 */ + + function xLimitOrOffsetClause($v) { + if ($sub_r = $this->x('(LIMIT|OFFSET)', $v)) { + $key = strtolower($sub_r[1]); + $sub_v = $sub_r[2]; + if ((list($sub_r, $sub_v) = $this->xINTEGER($sub_v)) && ($sub_r !== false)) { + return array(array($key =>$sub_r), $sub_v); + } + if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && ($sub_r !== false)) { + return array(array($key =>$sub_r), $sub_v); + } + } + return array(0, $v); + } + + /* 16 */ + + function xOrderClause($v) { + if ($sub_r = $this->x('ORDER BY\s+', $v)) { + $sub_v = $sub_r[1]; + $r = array(); + while ((list($sub_r, $sub_v) = $this->xOrderCondition($sub_v)) && $sub_r) { + $r[] = $sub_r; + } + if (count($r)) { + return array($r, $sub_v); + } + else { + $this->addError('No order conditions specified.'); + } + } + return array(0, $v); + } + + /* 17, 27 */ + + function xOrderCondition($v) { + if ($sub_r = $this->x('(ASC|DESC)', $v)) { + $dir = strtolower($sub_r[1]); + $sub_v = $sub_r[2]; + if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $sub_r) { + $sub_r['direction'] = $dir; + return array($sub_r, $sub_v); + } + } + elseif ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) { + $sub_r['direction'] = 'asc'; + return array($sub_r, $sub_v); + } + elseif ((list($sub_r, $sub_v) = $this->xBrackettedExpression($v)) && $sub_r) { + return array($sub_r, $sub_v); + } + elseif ((list($sub_r, $sub_v) = $this->xBuiltInCall($v)) && $sub_r) { + $sub_r['direction'] = 'asc'; + return array($sub_r, $sub_v); + } + elseif ((list($sub_r, $sub_v) = $this->xFunctionCall($v)) && $sub_r) { + $sub_r['direction'] = 'asc'; + return array($sub_r, $sub_v); + } + return array(0, $v); + } + + /* 20 */ + + function xGroupGraphPattern($v) { + $pattern_id = substr(md5(uniqid(rand())), 0, 4); + if ($sub_r = $this->x('\{', $v)) { + $r = array('type' => 'group', 'patterns' => array()); + $sub_v = $sub_r[1]; + if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) { + $this->indexBnodes($sub_r, $pattern_id); + $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r); + } + do { + $proceed = 0; + if ((list($sub_r, $sub_v) = $this->xGraphPatternNotTriples($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + $pattern_id = substr(md5(uniqid(rand())), 0, 4); + $proceed = 1; + } + elseif ((list($sub_r, $sub_v) = $this->xFilter($sub_v)) && $sub_r) { + $r['patterns'][] = array('type' => 'filter', 'constraint' => $sub_r); + $proceed = 1; + } + if ($sub_r = $this->x('\.', $sub_v)) { + $sub_v = $sub_r[1]; + } + if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) { + $this->indexBnodes($sub_r, $pattern_id); + $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r); + $proceed = 1; + } + if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + $proceed = 1; + } + } while ($proceed); + if ($sub_r = $this->x('\}', $sub_v)) { + $sub_v = $sub_r[1]; + return array($r, $sub_v); + } + $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($sub_v, 0, 30)); + $this->addError('Incomplete or invalid Group Graph pattern. Could not handle "' . $rest . '"'); + } + return array(0, $v); + } + + function indexBnodes($triples, $pattern_id) { + $index_id = count($this->bnode_pattern_index['patterns']); + $index_id = $pattern_id; + $this->bnode_pattern_index['patterns'][] = $triples; + foreach ($triples as $t) { + foreach (array('s', 'p', 'o') as $term) { + if ($t[$term . '_type'] == 'bnode') { + $val = $t[$term]; + if (isset($this->bnode_pattern_index['bnodes'][$val]) && ($this->bnode_pattern_index['bnodes'][$val] != $index_id)) { + $this->addError('Re-used bnode label "' .$val. '" across graph patterns'); + } + else { + $this->bnode_pattern_index['bnodes'][$val] = $index_id; + } + } + } + } + } + + /* 22.., 25.. */ + + function xGraphPatternNotTriples($v) { + if ((list($sub_r, $sub_v) = $this->xOptionalGraphPattern($v)) && $sub_r) { + return array($sub_r, $sub_v); + } + if ((list($sub_r, $sub_v) = $this->xGraphGraphPattern($v)) && $sub_r) { + return array($sub_r, $sub_v); + } + $r = array('type' => 'union', 'patterns' => array()); + $sub_v = $v; + do { + $proceed = 0; + if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + if ($sub_r = $this->x('UNION', $sub_v)) { + $sub_v = $sub_r[1]; + $proceed = 1; + } + } + } while ($proceed); + $pc = count($r['patterns']); + if ($pc == 1) { + return array($r['patterns'][0], $sub_v); + } + elseif ($pc > 1) { + return array($r, $sub_v); + } + return array(0, $v); + } + + /* 23 */ + + function xOptionalGraphPattern($v) { + if ($sub_r = $this->x('OPTIONAL', $v)) { + $sub_v = $sub_r[1]; + if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) { + return array(array('type' => 'optional', 'patterns' => $sub_r['patterns']), $sub_v); + } + $this->addError('Missing or invalid Group Graph Pattern after OPTIONAL'); + } + return array(0, $v); + } + + /* 24.. */ + + function xGraphGraphPattern($v) { + if ($sub_r = $this->x('GRAPH', $v)) { + $sub_v = $sub_r[1]; + $r = array('type' => 'graph', 'var' => '', 'uri' => '', 'patterns' => array()); + if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) { + $r['var'] = $sub_r; + } + elseif ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) { + $r['uri'] = $sub_r; + } + if ($r['var'] || $r['uri']) { + if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + return array($r, $sub_v); + } + $this->addError('Missing or invalid Graph Pattern'); + } + } + return array(0, $v); + } + + /* 26.., 27.. */ + + function xFilter($v) { + if ($r = $this->x('FILTER', $v)) { + $sub_v = $r[1]; + if ((list($r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $r) { + return array($r, $sub_v); + } + if ((list($r, $sub_v) = $this->xBuiltInCall($sub_v)) && $r) { + return array($r, $sub_v); + } + if ((list($r, $sub_v) = $this->xFunctionCall($sub_v)) && $r) { + return array($r, $sub_v); + } + $this->addError('Incomplete FILTER'); + } + return array(0, $v); + } + + /* 28.. */ + + function xFunctionCall($v) { + if ((list($r, $sub_v) = $this->xIRIref($v)) && $r) { + if ((list($sub_r, $sub_v) = $this->xArgList($sub_v)) && $sub_r) { + return array(array('type' => 'function_call', 'uri' => $r, 'args' => $sub_r), $sub_v); + } + } + return array(0, $v); + } + + /* 29 */ + + function xArgList($v) { + $r = array(); + $sub_v = $v; + $closed = 0; + if ($sub_r = $this->x('\(', $sub_v)) { + $sub_v = $sub_r[1]; + do { + $proceed = 0; + if ((list($sub_r, $sub_v) = $this->xExpression($sub_v)) && $sub_r) { + $r[] = $sub_r; + if ($sub_r = $this->x('\,', $sub_v)) { + $sub_v = $sub_r[1]; + $proceed = 1; + } + } + if ($sub_r = $this->x('\)', $sub_v)) { + $sub_v = $sub_r[1]; + $closed = 1; + $proceed = 0; + } + } while ($proceed); + } + return $closed ? array($r, $sub_v) : array(0, $v); + } + + /* 30, 31 */ + + function xConstructTemplate($v) { + if ($sub_r = $this->x('\{', $v)) { + $r = array(); + if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_r[1])) && is_array($sub_r)) { + $r = $sub_r; + } + if ($sub_r = $this->x('\}', $sub_v)) { + return array($r, $sub_r[1]); + } + } + return array(0, $v); + } + + /* 46, 47 */ + + function xExpression($v) { + if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($v)) && $sub_r) { + $r = array('type' => 'expression', 'sub_type' => 'or', 'patterns' => array($sub_r)); + do { + $proceed = 0; + if ($sub_r = $this->x('\|\|', $sub_v)) { + $sub_v = $sub_r[1]; + if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + $proceed = 1; + } + } + } while ($proceed); + return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v); + } + return array(0, $v); + } + + /* 48.., 49.. */ + + function xConditionalAndExpression($v) { + if ((list($sub_r, $sub_v) = $this->xRelationalExpression($v)) && $sub_r) { + $r = array('type' => 'expression', 'sub_type' => 'and', 'patterns' => array($sub_r)); + do { + $proceed = 0; + if ($sub_r = $this->x('\&\&', $sub_v)) { + $sub_v = $sub_r[1]; + if ((list($sub_r, $sub_v) = $this->xRelationalExpression($sub_v)) && $sub_r) { + $r['patterns'][] = $sub_r; + $proceed = 1; + } + } + } while ($proceed); + return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v); + } + return array(0, $v); + } + + /* 50, 51 */ + + function xRelationalExpression($v) { + if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($v)) && $sub_r) { + $r = array('type' => 'expression', 'sub_type' => 'relational', 'patterns' => array($sub_r)); + do { + $proceed = 0; + /* don't mistake '<' + uriref with '<'-operator ("longest token" rule) */ + if ((list($sub_r, $sub_v) = $this->xIRI_REF($sub_v)) && $sub_r) { + $this->addError('Expected operator, found IRIref: "'.$sub_r.'".'); + } + if ($sub_r = $this->x('(\!\=|\=\=|\=|\<\=|\>\=|\<|\>)', $sub_v)) { + $op = $sub_r[1]; + $sub_v = $sub_r[2]; + $r['operator'] = $op; + if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($sub_v)) && $sub_r) { + //$sub_r['operator'] = $op; + $r['patterns'][] = $sub_r; + $proceed = 1; + } + } + } while ($proceed); + return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v); + } + return array(0, $v); + } + + /* 52 */ + + function xAdditiveExpression($v) { + if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($v)) && $sub_r) { + $r = array('type' => 'expression', 'sub_type' => 'additive', 'patterns' => array($sub_r)); + do { + $proceed = 0; + if ($sub_r = $this->x('(\+|\-)', $sub_v)) { + $op = $sub_r[1]; + $sub_v = $sub_r[2]; + if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($sub_v)) && $sub_r) { + $sub_r['operator'] = $op; + $r['patterns'][] = $sub_r; + $proceed = 1; + } + elseif ((list($sub_r, $sub_v) = $this->xNumericLiteral($sub_v)) && $sub_r) { + $r['patterns'][] = array('type' => 'numeric', 'operator' => $op, 'value' => $sub_r); + $proceed = 1; + } + } + } while ($proceed); + //return array($r, $sub_v); + return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v); + } + return array(0, $v); + } + + /* 53 */ + + function xMultiplicativeExpression($v) { + if ((list($sub_r, $sub_v) = $this->xUnaryExpression($v)) && $sub_r) { + $r = array('type' => 'expression', 'sub_type' => 'multiplicative', 'patterns' => array($sub_r)); + do { + $proceed = 0; + if ($sub_r = $this->x('(\*|\/)', $sub_v)) { + $op = $sub_r[1]; + $sub_v = $sub_r[2]; + if ((list($sub_r, $sub_v) = $this->xUnaryExpression($sub_v)) && $sub_r) { + $sub_r['operator'] = $op; + $r['patterns'][] = $sub_r; + $proceed = 1; + } + } + } while ($proceed); + return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v); + } + return array(0, $v); + } + + /* 54 */ + + function xUnaryExpression($v) { + $sub_v = $v; + $op = ''; + if ($sub_r = $this->x('(\!|\+|\-)', $sub_v)) { + $op = $sub_r[1]; + $sub_v = $sub_r[2]; + } + if ((list($sub_r, $sub_v) = $this->xPrimaryExpression($sub_v)) && $sub_r) { + if (!is_array($sub_r)) { + $sub_r = array('type' => 'unary', 'expression' => $sub_r); + } + elseif ($sub_op = $this->v1('operator', '', $sub_r)) { + $ops = array('!!' => '', '++' => '+', '--' => '+', '+-' => '-', '-+' => '-'); + $op = isset($ops[$op . $sub_op]) ? $ops[$op . $sub_op] : $op . $sub_op; + } + $sub_r['operator'] = $op; + return array($sub_r, $sub_v); + } + return array(0, $v); + } + + /* 55 */ + + function xPrimaryExpression($v) { + foreach (array('BrackettedExpression', 'BuiltInCall', 'IRIrefOrFunction', 'RDFLiteral', 'NumericLiteral', 'BooleanLiteral', 'Var', 'Placeholder') as $type) { + $m = 'x' . $type; + if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) { + return array($sub_r, $sub_v); + } + } + return array(0, $v); + } + + /* 56 */ + + function xBrackettedExpression($v) { + if ($r = $this->x('\(', $v)) { + if ((list($r, $sub_v) = $this->xExpression($r[1])) && $r) { + if ($sub_r = $this->x('\)', $sub_v)) { + return array($r, $sub_r[1]); + } + } + } + return array(0, $v); + } + + /* 57.., 58.. */ + + function xBuiltInCall($v) { + if ($sub_r = $this->x('(str|lang|langmatches|datatype|bound|sameterm|isiri|isuri|isblank|isliteral|regex)\s*\(', $v)) { + $r = array('type' => 'built_in_call', 'call' => strtolower($sub_r[1])); + if ((list($sub_r, $sub_v) = $this->xArgList('(' . $sub_r[2])) && is_array($sub_r)) { + $r['args'] = $sub_r; + return array($r, $sub_v); + } + } + return array(0, $v); + } + + /* 59.. */ + + function xIRIrefOrFunction($v) { + if ((list($r, $v) = $this->xIRIref($v)) && $r) { + if ((list($sub_r, $sub_v) = $this->xArgList($v)) && is_array($sub_r)) { + return array(array('type' => 'function', 'uri' => $r, 'args' => $sub_r), $sub_v); + } + return array(array('type' => 'uri', 'uri' => $r), $sub_v); + } + } + + /* 70.. @@sync with TurtleParser */ + + function xIRI_REF($v) { + if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) { + return array($r[1], $r[2]); + } + elseif ($r = $this->x('\<([^\<\>\s\"\|\^`]*)\>', $v)) { + return array($r[1] ? $r[1] : true, $r[2]); + } + /* allow reserved chars in obvious IRIs */ + elseif ($r = $this->x('\<(https?\:[^\s][^\<\>]*)\>', $v)) { + return array($r[1] ? $r[1] : true, $r[2]); + } + return array(0, $v); + } + +}