danielebarchiesi@4
|
1 <?php
|
danielebarchiesi@4
|
2 /*
|
danielebarchiesi@4
|
3 homepage: http://arc.semsol.org/
|
danielebarchiesi@4
|
4 license: http://arc.semsol.org/license
|
danielebarchiesi@4
|
5
|
danielebarchiesi@4
|
6 class: ARC2 SPARQLScript Parser (SPARQL+ + functions)
|
danielebarchiesi@4
|
7 author: Benjamin Nowack
|
danielebarchiesi@4
|
8 version: 2010-11-16
|
danielebarchiesi@4
|
9 */
|
danielebarchiesi@4
|
10
|
danielebarchiesi@4
|
11 ARC2::inc('ARC2_SPARQLPlusParser');
|
danielebarchiesi@4
|
12
|
danielebarchiesi@4
|
13 class ARC2_SPARQLScriptParser extends ARC2_SPARQLPlusParser {
|
danielebarchiesi@4
|
14
|
danielebarchiesi@4
|
15 function __construct($a, &$caller) {
|
danielebarchiesi@4
|
16 parent::__construct($a, $caller);
|
danielebarchiesi@4
|
17 }
|
danielebarchiesi@4
|
18
|
danielebarchiesi@4
|
19 function __init() {
|
danielebarchiesi@4
|
20 parent::__init();
|
danielebarchiesi@4
|
21 }
|
danielebarchiesi@4
|
22
|
danielebarchiesi@4
|
23 /* */
|
danielebarchiesi@4
|
24
|
danielebarchiesi@4
|
25 function parse($v, $src = '', $iso_fallback = 'ignore') {
|
danielebarchiesi@4
|
26 $this->setDefaultPrefixes();
|
danielebarchiesi@4
|
27 $this->base = $src ? $this->calcBase($src) : ARC2::getScriptURI();
|
danielebarchiesi@4
|
28 $this->blocks = array();
|
danielebarchiesi@4
|
29 $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
danielebarchiesi@4
|
30 do {
|
danielebarchiesi@4
|
31 $proceed = 0;
|
danielebarchiesi@4
|
32 if ((list($r, $v) = $this->xScriptBlock($v)) && $r) {
|
danielebarchiesi@4
|
33 $this->blocks[] = $r;
|
danielebarchiesi@4
|
34 $proceed = 1;
|
danielebarchiesi@4
|
35 }
|
danielebarchiesi@4
|
36 $this->unparsed_code = trim($v);
|
danielebarchiesi@4
|
37 } while ($proceed);
|
danielebarchiesi@4
|
38 if (trim($this->unparsed_code) && !$this->getErrors()) {
|
danielebarchiesi@4
|
39 $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
|
danielebarchiesi@4
|
40 $msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax Error';
|
danielebarchiesi@4
|
41 $this->addError($msg);
|
danielebarchiesi@4
|
42 }
|
danielebarchiesi@4
|
43 }
|
danielebarchiesi@4
|
44
|
danielebarchiesi@4
|
45 function getScriptBlocks() {
|
danielebarchiesi@4
|
46 return $this->v('blocks', array());
|
danielebarchiesi@4
|
47 }
|
danielebarchiesi@4
|
48
|
danielebarchiesi@4
|
49 /* */
|
danielebarchiesi@4
|
50
|
danielebarchiesi@4
|
51 function xScriptBlock($v) {
|
danielebarchiesi@4
|
52 /* comment removal */
|
danielebarchiesi@4
|
53 while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) $v = $m[2];
|
danielebarchiesi@4
|
54 /* BaseDecl */
|
danielebarchiesi@4
|
55 if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
|
danielebarchiesi@4
|
56 $this->base = $sub_r;
|
danielebarchiesi@4
|
57 }
|
danielebarchiesi@4
|
58 /* PrefixDecl */
|
danielebarchiesi@4
|
59 while ((list($r, $v) = $this->xPrefixDecl($v)) && $r) {
|
danielebarchiesi@4
|
60 $this->prefixes[$r['prefix']] = $r['uri'];
|
danielebarchiesi@4
|
61 }
|
danielebarchiesi@4
|
62 /* EndpointDecl */
|
danielebarchiesi@4
|
63 if ((list($r, $v) = $this->xEndpointDecl($v)) && $r) {
|
danielebarchiesi@4
|
64 return array($r, $v);
|
danielebarchiesi@4
|
65 }
|
danielebarchiesi@4
|
66 /* Return */
|
danielebarchiesi@4
|
67 if ((list($r, $v) = $this->xReturn($v)) && $r) {
|
danielebarchiesi@4
|
68 return array($r, $v);
|
danielebarchiesi@4
|
69 }
|
danielebarchiesi@4
|
70 /* Assignment */
|
danielebarchiesi@4
|
71 if ((list($r, $v) = $this->xAssignment($v)) && $r) {
|
danielebarchiesi@4
|
72 return array($r, $v);
|
danielebarchiesi@4
|
73 }
|
danielebarchiesi@4
|
74 /* IFBlock */
|
danielebarchiesi@4
|
75 if ((list($r, $v) = $this->xIFBlock($v)) && $r) {
|
danielebarchiesi@4
|
76 return array($r, $v);
|
danielebarchiesi@4
|
77 }
|
danielebarchiesi@4
|
78 /* FORBlock */
|
danielebarchiesi@4
|
79 if ((list($r, $v) = $this->xFORBlock($v)) && $r) {
|
danielebarchiesi@4
|
80 return array($r, $v);
|
danielebarchiesi@4
|
81 }
|
danielebarchiesi@4
|
82 /* String */
|
danielebarchiesi@4
|
83 if ((list($r, $v) = $this->xString($v)) && $r) {
|
danielebarchiesi@4
|
84 return array($r, $v);
|
danielebarchiesi@4
|
85 }
|
danielebarchiesi@4
|
86 /* FunctionCall */
|
danielebarchiesi@4
|
87 if ((list($r, $v) = $this->xFunctionCall($v)) && $r) {
|
danielebarchiesi@4
|
88 return array($r, ltrim($v, ';'));
|
danielebarchiesi@4
|
89 }
|
danielebarchiesi@4
|
90 /* Query */
|
danielebarchiesi@4
|
91 $prev_r = $this->r;
|
danielebarchiesi@4
|
92 $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
danielebarchiesi@4
|
93 if ((list($r, $rest) = $this->xQuery($v)) && $r) {
|
danielebarchiesi@4
|
94 $q = $rest ? trim(substr($v, 0, -strlen($rest))) : trim($v);
|
danielebarchiesi@4
|
95 $v = $rest;
|
danielebarchiesi@4
|
96 $r = array_merge($this->r, array(
|
danielebarchiesi@4
|
97 'type' => 'query',
|
danielebarchiesi@4
|
98 'query_type' => $r['type'],
|
danielebarchiesi@4
|
99 'query' => $q,
|
danielebarchiesi@4
|
100 //'prefixes' => $this->prefixes,
|
danielebarchiesi@4
|
101 'base' => $this->base,
|
danielebarchiesi@4
|
102 //'infos' => $r
|
danielebarchiesi@4
|
103 ));
|
danielebarchiesi@4
|
104 return array($r, $v);
|
danielebarchiesi@4
|
105 }
|
danielebarchiesi@4
|
106 else {
|
danielebarchiesi@4
|
107 $this->r = $prev_r;
|
danielebarchiesi@4
|
108 }
|
danielebarchiesi@4
|
109 return array(0, $v);
|
danielebarchiesi@4
|
110 }
|
danielebarchiesi@4
|
111
|
danielebarchiesi@4
|
112 function xBlockSet($v) {
|
danielebarchiesi@4
|
113 if (!$r = $this->x("\{", $v)) return array(0, $v);
|
danielebarchiesi@4
|
114 $blocks = array();
|
danielebarchiesi@4
|
115 $sub_v = $r[1];
|
danielebarchiesi@4
|
116 while ((list($sub_r, $sub_v) = $this->xScriptBlock($sub_v)) && $sub_r) {
|
danielebarchiesi@4
|
117 $blocks[] = $sub_r;
|
danielebarchiesi@4
|
118 }
|
danielebarchiesi@4
|
119 if (!$sub_r = $this->x("\}", $sub_v)) return array(0, $v);
|
danielebarchiesi@4
|
120 $sub_v = $sub_r[1];
|
danielebarchiesi@4
|
121 return array(array('type' => 'block_set', 'blocks' => $blocks), $sub_v);
|
danielebarchiesi@4
|
122 }
|
danielebarchiesi@4
|
123
|
danielebarchiesi@4
|
124 /* s2 */
|
danielebarchiesi@4
|
125
|
danielebarchiesi@4
|
126 function xEndpointDecl($v) {
|
danielebarchiesi@4
|
127 if ($r = $this->x("ENDPOINT\s+", $v)) {
|
danielebarchiesi@4
|
128 if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
|
danielebarchiesi@4
|
129 $r = $this->calcURI($r, $this->base);
|
danielebarchiesi@4
|
130 if ($sub_r = $this->x('\.', $sub_v)) {
|
danielebarchiesi@4
|
131 $sub_v = $sub_r[1];
|
danielebarchiesi@4
|
132 }
|
danielebarchiesi@4
|
133 return array(
|
danielebarchiesi@4
|
134 array('type' => 'endpoint_decl', 'endpoint' => $r),
|
danielebarchiesi@4
|
135 $sub_v
|
danielebarchiesi@4
|
136 );
|
danielebarchiesi@4
|
137 }
|
danielebarchiesi@4
|
138 }
|
danielebarchiesi@4
|
139 return array(0, $v);
|
danielebarchiesi@4
|
140 }
|
danielebarchiesi@4
|
141
|
danielebarchiesi@4
|
142 /* s3 */
|
danielebarchiesi@4
|
143
|
danielebarchiesi@4
|
144 function xAssignment($v) {
|
danielebarchiesi@4
|
145 /* Var */
|
danielebarchiesi@4
|
146 list($r, $sub_v) = $this->xVar($v);
|
danielebarchiesi@4
|
147 if (!$r) return array(0, $v);
|
danielebarchiesi@4
|
148 $var = $r;
|
danielebarchiesi@4
|
149 /* := | = */
|
danielebarchiesi@4
|
150 if (!$sub_r = $this->x("\:?\=", $sub_v)) return array(0, $v);
|
danielebarchiesi@4
|
151 $sub_v = $sub_r[1];
|
danielebarchiesi@4
|
152 /* try String */
|
danielebarchiesi@4
|
153 list($r, $sub_v) = $this->xString($sub_v);
|
danielebarchiesi@4
|
154 if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'string', 'string' => $r), ltrim($sub_v, '; '));
|
danielebarchiesi@4
|
155 /* try VarMerge */
|
danielebarchiesi@4
|
156 list($r, $sub_v) = $this->xVarMerge($sub_v);
|
danielebarchiesi@4
|
157 if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var_merge', 'var2' => $r[0], 'var3' => $r[1]), ltrim($sub_v, '; '));
|
danielebarchiesi@4
|
158 /* try Var */
|
danielebarchiesi@4
|
159 list($r, $sub_v) = $this->xVar($sub_v);
|
danielebarchiesi@4
|
160 if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var', 'var2' => $r), ltrim($sub_v, '; '));
|
danielebarchiesi@4
|
161 /* try function */
|
danielebarchiesi@4
|
162 list($r, $sub_v) = $this->xFunctionCall($sub_v);
|
danielebarchiesi@4
|
163 if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'function_call', 'function_call' => $r), ltrim($sub_v, '; '));
|
danielebarchiesi@4
|
164 /* try Placeholder */
|
danielebarchiesi@4
|
165 list($r, $sub_v) = $this->xPlaceholder($sub_v);
|
danielebarchiesi@4
|
166 if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'placeholder', 'placeholder' => $r), ltrim($sub_v, '; '));
|
danielebarchiesi@4
|
167 /* try query */
|
danielebarchiesi@4
|
168 $prev_r = $this->r;
|
danielebarchiesi@4
|
169 $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
danielebarchiesi@4
|
170 list($r, $rest) = $this->xQuery($sub_v);
|
danielebarchiesi@4
|
171 if (!$r) {
|
danielebarchiesi@4
|
172 $this->r = $prev_r;
|
danielebarchiesi@4
|
173 return array(0, $v);
|
danielebarchiesi@4
|
174 }
|
danielebarchiesi@4
|
175 else {
|
danielebarchiesi@4
|
176 $q = $rest ? trim(substr($sub_v, 0, -strlen($rest))) : trim($sub_v);
|
danielebarchiesi@4
|
177 return array(
|
danielebarchiesi@4
|
178 array(
|
danielebarchiesi@4
|
179 'type' => 'assignment',
|
danielebarchiesi@4
|
180 'var' => $var,
|
danielebarchiesi@4
|
181 'sub_type' => 'query',
|
danielebarchiesi@4
|
182 'query' => array_merge($this->r, array(
|
danielebarchiesi@4
|
183 'type' => 'query',
|
danielebarchiesi@4
|
184 'query_type' => $r['type'],
|
danielebarchiesi@4
|
185 'query' => $q,
|
danielebarchiesi@4
|
186 'base' => $this->base,
|
danielebarchiesi@4
|
187 )),
|
danielebarchiesi@4
|
188 ),
|
danielebarchiesi@4
|
189 ltrim($rest, '; ')
|
danielebarchiesi@4
|
190 );
|
danielebarchiesi@4
|
191 }
|
danielebarchiesi@4
|
192 }
|
danielebarchiesi@4
|
193
|
danielebarchiesi@4
|
194 function xReturn($v) {
|
danielebarchiesi@4
|
195 if ($r = $this->x("return\s+", $v)) {
|
danielebarchiesi@4
|
196 /* fake assignment which accepts same right-hand values */
|
danielebarchiesi@4
|
197 $sub_v = '$__return_value__ := ' . $r[1];
|
danielebarchiesi@4
|
198 if ((list($r, $sub_v) = $this->xAssignment($sub_v)) && $r) {
|
danielebarchiesi@4
|
199 $r['type'] = 'return';
|
danielebarchiesi@4
|
200 return array($r, $sub_v);
|
danielebarchiesi@4
|
201 }
|
danielebarchiesi@4
|
202 }
|
danielebarchiesi@4
|
203 return array(0, $v);
|
danielebarchiesi@4
|
204 }
|
danielebarchiesi@4
|
205
|
danielebarchiesi@4
|
206 /* s4 'IF' BrackettedExpression '{' Script '}' ( 'ELSE' '{' Script '}')? */
|
danielebarchiesi@4
|
207
|
danielebarchiesi@4
|
208 function xIFBlock($v) {
|
danielebarchiesi@4
|
209 if ($r = $this->x("IF\s*", $v)) {
|
danielebarchiesi@4
|
210 if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($r[1])) && $sub_r) {
|
danielebarchiesi@4
|
211 $cond = $sub_r;
|
danielebarchiesi@4
|
212 if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
|
danielebarchiesi@4
|
213 $blocks = $sub_r['blocks'];
|
danielebarchiesi@4
|
214 /* else */
|
danielebarchiesi@4
|
215 $else_blocks = array();
|
danielebarchiesi@4
|
216 $rest = $sub_v;
|
danielebarchiesi@4
|
217 if ($sub_r = $this->x("ELSE\s*", $sub_v)) {
|
danielebarchiesi@4
|
218 if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_r[1])) && $sub_r) {
|
danielebarchiesi@4
|
219 $else_blocks = $sub_r['blocks'];
|
danielebarchiesi@4
|
220 }
|
danielebarchiesi@4
|
221 else {
|
danielebarchiesi@4
|
222 $sub_v = $rest;
|
danielebarchiesi@4
|
223 }
|
danielebarchiesi@4
|
224 }
|
danielebarchiesi@4
|
225 return array(
|
danielebarchiesi@4
|
226 array(
|
danielebarchiesi@4
|
227 'type' => 'ifblock',
|
danielebarchiesi@4
|
228 'condition' => $cond,
|
danielebarchiesi@4
|
229 'blocks' => $blocks,
|
danielebarchiesi@4
|
230 'else_blocks' => $else_blocks,
|
danielebarchiesi@4
|
231 ),
|
danielebarchiesi@4
|
232 $sub_v
|
danielebarchiesi@4
|
233 );
|
danielebarchiesi@4
|
234 }
|
danielebarchiesi@4
|
235 }
|
danielebarchiesi@4
|
236 }
|
danielebarchiesi@4
|
237 return array(0, $v);
|
danielebarchiesi@4
|
238 }
|
danielebarchiesi@4
|
239
|
danielebarchiesi@4
|
240 /* s5 'FOR' '(' Var 'IN' Var ')' '{' Script '}' */
|
danielebarchiesi@4
|
241
|
danielebarchiesi@4
|
242 function xFORBlock($v) {
|
danielebarchiesi@4
|
243 if ($r = $this->x("FOR\s*\(\s*[\$\?]([^\s]+)\s+IN\s+[\$\?]([^\s]+)\s*\)", $v)) {/* @@todo split into sub-patterns? */
|
danielebarchiesi@4
|
244 $iterator = $r[1];
|
danielebarchiesi@4
|
245 $set_var = $r[2];
|
danielebarchiesi@4
|
246 $sub_v = $r[3];
|
danielebarchiesi@4
|
247 if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
|
danielebarchiesi@4
|
248 return array(
|
danielebarchiesi@4
|
249 array(
|
danielebarchiesi@4
|
250 'type' => 'forblock',
|
danielebarchiesi@4
|
251 'set' => $set_var,
|
danielebarchiesi@4
|
252 'iterator' => $iterator,
|
danielebarchiesi@4
|
253 'blocks' => $sub_r['blocks']
|
danielebarchiesi@4
|
254 ),
|
danielebarchiesi@4
|
255 $sub_v
|
danielebarchiesi@4
|
256 );
|
danielebarchiesi@4
|
257 }
|
danielebarchiesi@4
|
258 }
|
danielebarchiesi@4
|
259 return array(0, $v);
|
danielebarchiesi@4
|
260 }
|
danielebarchiesi@4
|
261
|
danielebarchiesi@4
|
262 /* s6 Var '+' Var */
|
danielebarchiesi@4
|
263
|
danielebarchiesi@4
|
264 function xVarMerge($v) {
|
danielebarchiesi@4
|
265 if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
|
danielebarchiesi@4
|
266 $var1 = $sub_r;
|
danielebarchiesi@4
|
267 if ($sub_r = $this->x("\+", $sub_v)) {
|
danielebarchiesi@4
|
268 $sub_v = $sub_r[1];
|
danielebarchiesi@4
|
269 if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
|
danielebarchiesi@4
|
270 return array(
|
danielebarchiesi@4
|
271 array($var1, $sub_r),
|
danielebarchiesi@4
|
272 $sub_v
|
danielebarchiesi@4
|
273 );
|
danielebarchiesi@4
|
274 }
|
danielebarchiesi@4
|
275 }
|
danielebarchiesi@4
|
276 }
|
danielebarchiesi@4
|
277 return array(0, $v);
|
danielebarchiesi@4
|
278 }
|
danielebarchiesi@4
|
279
|
danielebarchiesi@4
|
280 }
|