/arc/sparqlscript/ARC2_SPARQLScriptParser.php

https://github.com/kwijibo/sparql-proxy · PHP · 262 lines · 205 code · 22 blank · 35 comment · 56 complexity · f8a37c946a49b130202844f619356908 MD5 · raw file

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