ARC2_SPARQLScriptParser.php 8.2 KB

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