PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/template_engines_bench/libs/lapa/Engine/LexisSmart.php

https://github.com/limb-php-framework/limb-tools
PHP | 795 lines | 598 code | 76 blank | 121 comment | 111 complexity | 5fd5eec43a7eccdf1899ad406a71b090 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1
  1. <?PHP
  2. /**
  3. * Lexis
  4. *
  5. * Lapa Template ToolKit
  6. *
  7. * PHP versions 5
  8. *
  9. * Copyright (c) 2000-2006 Stepanov Sergey
  10. *
  11. * LICENSE:
  12. *
  13. * This library is free software; you can redistribute it
  14. * and/or modify it under the terms of the GNU Lesser General
  15. * Public License as published by the Free Software Foundation;
  16. * either version 2.1 of the License, or (at your option) any
  17. * later version.
  18. *
  19. * This library is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * Lesser General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Lesser General Public
  25. * License along with this library; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. *
  28. * @package Lapa
  29. * @subpackage LapaEngine
  30. * @author Stepanov Sergey <StepanovSergey@tut.by>
  31. * @copyright 2007 Stepanov Sergey
  32. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  33. * @version v 0.5.7.3 2007/10/27
  34. */
  35. require_once('Exception.php');
  36. define('LAPA_INLINE_HTML', 1);
  37. define('LT_NEW_LINE', 2); //новая строка
  38. // переменные
  39. define('LT_VARIABLE', 3); // $var
  40. define('LT_CLASS_STATIC', 4); // признак вызова статического метода
  41. define('LT_VARIABLE_GLOBAL', 5); // глобальная переменная lapa
  42. define('LT_BOOL', 6); // true, false (0, 1)
  43. define('LT_VALUE', 7); // число, строка и т.д.
  44. // присвоение / вывод
  45. define('LT_EQUAL', 8); // =
  46. define('LT_CON_CAT', 9); // .. обьединение '' .. '', аналог php .
  47. define('LT_SET_ARRAY', 10); // => присваивание элемента в массиве
  48. // операторы сравнения
  49. define('LT_OPERATOR', 11); // != <> !== // == === // <= // =< // =< || * / % ^ && !
  50. define('LT_OPERATOR2', 12); // ++ --
  51. define('LT_OPERATOR3', 13); // !
  52. define('LT_OPERATOR4', 14); // - смена знака, зависит от контекста
  53. define('LT_OPERATOR5', 15); // is div even
  54. define('LT_ARRAY', 16);
  55. define('LT_ARRAY_CAST', 17);
  56. define('LT_OBJECT_GET', 18);
  57. //define('LT_PAAMAYIM_NEKUDOTAYIM', 19); // ::
  58. define('LT_OTHER', 29); //
  59. define('LT_FUNCTION', 21); //
  60. define('LT_STR_ARRAY', 22); // нереализован, простой строковой массив
  61. define('LT_OPEN_ARRAY_BRACKET', 23); // [
  62. define('LT_CLOSE_ARRAY_BRACKET', 24); // ]
  63. define('LT_OPEN_BRACKET', 25); // (
  64. define('LT_CLOSE_BRACKET', 26); // (
  65. define('LT_PARAMETR_DELIM', 27); // ,
  66. define('LT_CALL', 28);
  67. define('LT_EXT_FUNCTION', 29);
  68. define('LT_GET', 30);
  69. define('LT_END', 35);
  70. define('LT_END_FUNCTION', 38);
  71. define('LT_INSERT_TEMPLATE', 53);
  72. define('LT_INCLUDE_TEMPLATE', 54);
  73. define('LT_DIRECTIVE', 55);
  74. define('LT_MODIFICATOR', 56); // признак модификатора
  75. define('LT_ARGUMENT', 57); // признак параметра модификатора
  76. define('LT_STOP_COMPILER', 58); //
  77. define('LT_END_LAPA_SCRIPT', 59); // служебный, признак окончания шаблона
  78. define('LT_PARSER_DIRECTIVE', 60); // директивы парсера
  79. define('LT_COMMENT', 61); // комментарий
  80. define('LT_END_COMMENT', 62); // конец комментария
  81. define('LT_ERROR_AT', 63); // подавление ошибок
  82. class LapaEngineLexisSmart
  83. {
  84. protected $array_pattern_search = array(
  85. '!',
  86. '[A-Za-z_]+[0-9A-Za-z_]*', // любое допустимое слово (функции, переменные)
  87. '|[\s]', // пробел
  88. '|[\$]+', // начало переменной
  89. '|\n', // перевод строки
  90. '|[\d]+',
  91. '|\.\=', // .=
  92. '|\.\.|\.\=|\.', // .. .= .
  93. '|\=\>', // =>
  94. '|[\=\>]+', // === == =
  95. '|[\|]+', // || |
  96. '|\(', // (
  97. '|\#', // # признак конфигурационной переменной
  98. '|\)', // )
  99. '|[\*\/]+', // * */ /
  100. '|[\:]+', // : ::
  101. '|\[|\]', // [ и ]
  102. '|[\%\^\,\?]+', // % ^ , ?
  103. '|\+\=', // +=
  104. '|[\+]+', // ++ +
  105. '|[\-\>\=]+', // -> -= -- -
  106. '|[\&]+', // && &
  107. '|[\!\=]+', // !== != !
  108. '|\<\>', // <>
  109. '|[\<\=]+', // << <= <
  110. '|[\>\=]+', // >= >> >
  111. '|\\\\',
  112. '|"', // "
  113. "|'", // '
  114. '|\@',
  115. '|.', // кракозябы
  116. '!'
  117. );
  118. protected $known_tags = array(
  119. 'lapa' => array(LT_VARIABLE_GLOBAL),
  120. 'call' => array(LT_CALL),
  121. '=' => array(LT_GET),
  122. 'set' => array(LT_CALL),
  123. 'get' => array(LT_GET),
  124. 'directive' => array(LT_DIRECTIVE),
  125. 'insert_template' => array(LT_INSERT_TEMPLATE),
  126. 'include' => array(LT_INCLUDE_TEMPLATE),
  127. 'comment' => array(LT_COMMENT),
  128. );
  129. protected $known_tags_operator = array(
  130. 'lapa' => array(LT_VARIABLE_GLOBAL),
  131. 'and' => array(LT_OPERATOR, '&&'),
  132. 'or' => array(LT_OPERATOR, '||'),
  133. 'xor' => array(LT_OPERATOR, 'xor'),
  134. 'eq' => array(LT_OPERATOR, '=='),
  135. 'ne' => array(LT_OPERATOR, '!='),
  136. 'neq' => array(LT_OPERATOR, '!='),
  137. 'gt' => array(LT_OPERATOR, '>'),
  138. 'lt' => array(LT_OPERATOR, '<'),
  139. 'ge' => array(LT_OPERATOR, '>='),
  140. 'gte' => array(LT_OPERATOR, '>='),
  141. 'le' => array(LT_OPERATOR, '<='),
  142. 'lte' => array(LT_OPERATOR, '<='),
  143. 'not' => array(LT_OPERATOR3, '!'),
  144. 'array' => array(LT_ARRAY_CAST ),
  145. 'on' => array(LT_BOOL, 'true'),
  146. 'true' => array(LT_BOOL, 'true'),
  147. 'yes' => array(LT_BOOL, 'true'),
  148. 'off' => array(LT_BOOL, 'false'),
  149. 'false' => array(LT_BOOL, 'false'),
  150. 'no' => array(LT_BOOL, 'false'),
  151. '[' => array(LT_OPEN_ARRAY_BRACKET, '['),
  152. ']' => array(LT_CLOSE_ARRAY_BRACKET, ']'),
  153. '%' => array(LT_OPERATOR, '%'),
  154. '^' => array(LT_OPERATOR, '^'),
  155. ',' => array(LT_PARAMETR_DELIM, ','),
  156. '?' => array(LT_CALL ),
  157. //'(' => array(LT_OPEN_BRACKET, '('),
  158. ')' => array(LT_CLOSE_BRACKET, ')'),
  159. '+' => array(LT_OPERATOR, '+'),
  160. '++' => array(LT_OPERATOR2, '++'),
  161. '+=' => array(LT_OPERATOR, '+='),
  162. '-' => array(LT_OPERATOR4, '-'),
  163. '--' => array(LT_OPERATOR2, '--'),
  164. '-=' => array(LT_OPERATOR, '-='),
  165. '->' => array(LT_OBJECT_GET, '->'),
  166. '&' => array(LT_OPERATOR, '&'),
  167. '&&' => array(LT_OPERATOR, '&&'),
  168. '=' => array(LT_EQUAL, '='),
  169. '=>' => array(LT_SET_ARRAY, '=>'),
  170. '==' => array(LT_OPERATOR, '=='),
  171. '===' => array(LT_OPERATOR, '==='),
  172. '!' => array(LT_OPERATOR3, '!'),
  173. '!=' => array(LT_OPERATOR, '!='),
  174. '!==' => array(LT_OPERATOR, '!=='),
  175. '<' => array(LT_OPERATOR, '<'),
  176. '<=' => array(LT_OPERATOR, '<='),
  177. '<>' => array(LT_OPERATOR, '!='),
  178. '<<' => array(LT_OPERATOR, '<<'),
  179. '>' => array(LT_OPERATOR, '>'),
  180. '>=' => array(LT_OPERATOR, '>='),
  181. '>>' => array(LT_OPERATOR, '>>'),
  182. '|' => array(LT_MODIFICATOR, '|'),
  183. '||' => array(LT_OPERATOR, '||'),
  184. '.' => array(LT_ARRAY, '.'),
  185. '.=' => array(LT_OPERATOR, '.='),
  186. ':' => array(LT_ARGUMENT, ':'),
  187. '@' => array(LT_ERROR_AT, '@')
  188. );
  189. protected $known_end_tags = array(
  190. 'comment' => array(LT_END_COMMENT),
  191. );
  192. protected $known_tags2 = array(
  193. '*' => array(LT_OPERATOR, '*'),
  194. '/' => array(LT_OPERATOR, '/'),
  195. '(' => array(LT_OPEN_BRACKET, '('),
  196. '..' => array(LT_CON_CAT, '.'),
  197. );
  198. protected $known_is_operator = array(
  199. 'notdivby' => array(LT_OPERATOR5, 'notdivby', true),
  200. 'divby' => array(LT_OPERATOR5, 'divby', true),
  201. 'noteven' => array(LT_OPERATOR5, 'noteven', false),
  202. 'even' => array(LT_OPERATOR5, 'even', false),
  203. 'notevenby' => array(LT_OPERATOR5, 'notevenby', true),
  204. 'evenby' => array(LT_OPERATOR5, 'evenby', true),
  205. 'notodd' => array(LT_OPERATOR5, 'notodd', false),
  206. 'odd' => array(LT_OPERATOR5, 'odd', false),
  207. 'notoddby' => array(LT_OPERATOR5, 'notoddby', true),
  208. 'oddby' => array(LT_OPERATOR5, 'oddby', true),
  209. );
  210. protected $state_tpl = false;
  211. protected $pattern_search;
  212. /**
  213. * Пропущенные блоки
  214. *
  215. * @var array
  216. */
  217. protected $literal_text = array();
  218. /**
  219. * Пропущенные блоки с php кодом
  220. *
  221. * @var array
  222. */
  223. protected $php_text = array();
  224. /**
  225. * Текущие настройки
  226. *
  227. * @var array
  228. */
  229. protected $options = array();
  230. /**
  231. * текущая строка шаблона
  232. *
  233. * @var string
  234. */
  235. protected $template_line;
  236. /**
  237. * Имя шаблона, используется для формирования исключений
  238. *
  239. * @var string
  240. */
  241. protected $template_name;
  242. /**
  243. * В случае ошибки, содержит объект исключения
  244. *
  245. * Узнать об ошибке можно через метод isError<br />, получить
  246. * объект можно вызвав метод lastError
  247. * @var object
  248. */
  249. protected $last_error;
  250. /**
  251. * Копируем настройки
  252. *
  253. * @param array $options
  254. * @return void
  255. */
  256. public function __setOptions(& $options)
  257. {
  258. $this->options = & $options;
  259. }
  260. public function __construct()
  261. {
  262. $this->pattern_search = implode('', $this->array_pattern_search);
  263. }
  264. public function isError()
  265. {
  266. if (is_object($this->last_error)) {
  267. return true;
  268. }
  269. return false;
  270. }
  271. public function lastError()
  272. {
  273. if (is_object($this->last_error)) {
  274. return $this->last_error;
  275. }
  276. return false;
  277. }
  278. /**
  279. *
  280. * разбор шаблона на лексемы
  281. *
  282. * @param string $source - строка содержит шаблон
  283. * @param string $templateName - имя шаблона
  284. */
  285. public function & lex($template_string, $template_name = 'Unknown') {
  286. $this->template_name = $template_name;
  287. $tokens[0] = $template_name;
  288. $tokens[1] = '';
  289. $lex_start = microtime(1); // служебный
  290. try {
  291. if ( strlen($template_string) ) {
  292. $tokens = & $this->splitTemplate($template_string, $tokens);
  293. }
  294. }catch (LapaEngineException $err) {
  295. $err->setTemplate($this->template_name, $this->template_line);
  296. $this->last_error = $err;
  297. // Only variable references should be returned by reference
  298. $r = false;
  299. return $r;
  300. }
  301. $tokens[1]['lex_time'] = microtime(1) - $lex_start;
  302. $tokens[1]['lex_line'] = $this->template_line;
  303. //print_r($tokens);
  304. return $tokens;
  305. }
  306. protected function prepareTemplate(& $template_string, & $arr_tpl) {
  307. $ldq = preg_quote($this->options['left_delimiter']);
  308. $rdq = preg_quote($this->options['right_delimiter']);
  309. $search['literal'] = "!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!si";
  310. $search['php'] = "!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!si";
  311. $search['tags'] = "!{$ldq}(.*?){$rdq}!s";
  312. $replace['literal'] = "!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!si";
  313. $replace['php'] = "!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!si";
  314. $replace['parse_text'] = '/(?<!\\\\|\\\\\$)([\$]{1,2}[a-zA-Z0-9_]+(\.|\w|\-\>)*)(?:[;]{1})/';
  315. //$replace['html_tags'] = '!(?:\<\s*)([\/]{0,1})(?:\s*tpl\s*:\s*)([^\/\>]*)(?:\/*\>)!si';
  316. //$replace['html_tags'] = '!(?:\<\s*)([\/]{0,1})(?:\s*tpl\s*\:\s*)([^\/\>]*)(?:\/*\>)!si';
  317. //$replace['html_tags'] = '!(?:\<\s*)([\/]{0,1})(?:\s*tpl\s*[\:]*\s*)(.*?)(?:\/*\s*\>)!si';
  318. $match = array();
  319. // есть команды для парсера
  320. if ($template_string[0] == '!') {
  321. // в работе
  322. }
  323. //удалим все каретки и табы
  324. $template_string = str_replace(array("\r", "\t"), '', $template_string);
  325. //$template_string = ' ' . $template_string;
  326. /* удалим блоки literal */
  327. $res = preg_match_all($search['literal'], $template_string, $match);
  328. if ($res) {
  329. $arr_tpl['literal'] = $match[1];
  330. $template_string = preg_replace($replace['literal'], $this->options['left_delimiter'] . "literal" . $this->options['right_delimiter'], $template_string);
  331. }
  332. /* удалим блоки php */
  333. $res = preg_match_all($search['php'], $template_string, $match);
  334. if ($res) {
  335. $arr_tpl['php'] = $match[1];
  336. $template_string = preg_replace($replace['php'], $this->options['left_delimiter'] . "php" . $this->options['right_delimiter'], $template_string);
  337. }
  338. if ( $this->options['parse_text'] ) {
  339. $template_string = preg_replace($replace['parse_text'], $this->options['left_delimiter'] . '$1' . $this->options['right_delimiter'], $template_string);
  340. }
  341. /* массив текста между тегами */
  342. $arr_tpl['text'] = preg_split("!{$ldq}.*?{$rdq}!s", $template_string);
  343. /* выделяем теги шаблонов */
  344. $res = preg_match_all($search['tags'], $template_string, $match);
  345. if ($res) {
  346. $arr_tpl['tags'] = $match[1];
  347. }
  348. //$this->debug_print($template_string);
  349. return true;
  350. }
  351. protected function & splitTemplate(& $template_string, $tokens)
  352. {
  353. $arr_tpl = array('literal'=>array(), 'php'=>array(), 'tags'=>array(), 'text'=>array());
  354. $this->prepareTemplate($template_string, $arr_tpl);
  355. unset($template_string);
  356. $text = & $arr_tpl['text'];
  357. $tags = & $arr_tpl['tags'];
  358. $count_tags = count($tags);
  359. if (count($arr_tpl['literal']) > 0) {
  360. $this->literal_text = $arr_tpl['literal'];
  361. }
  362. if (count($arr_tpl['php']) > 0) {
  363. $this->php_text = $arr_tpl['php'];
  364. }
  365. unset($arr_tpl);
  366. $this->template_line = 1;
  367. for ($i = 0; $count_tags > $i; ++$i) {
  368. $tmp_text = & $text[$i];
  369. $this->template_line += substr_count($tmp_text, "\n");
  370. $tokens[] = array(LAPA_INLINE_HTML, $tmp_text, $this->template_line);
  371. $tokens[] = array(LT_NEW_LINE, $this->template_line);
  372. $this->splitBlock($tags[$i], $tokens);
  373. }
  374. $this->template_line += substr_count($text[$i], "\n");
  375. if ($text[$i] != '') {
  376. $tokens[] = array(LAPA_INLINE_HTML, $text[$i], $this->template_line);
  377. }
  378. // почистим
  379. $this->literal_text = array();
  380. $this->php_text = array();
  381. return $tokens;
  382. }
  383. protected function splitBlock($tpl, & $tokens)
  384. {
  385. $new_line = true; $match = null;
  386. $res_count = preg_match_all($this->pattern_search, $tpl, $match);
  387. //echo '<pre>';
  388. //print_r($this->pattern_search);
  389. if ( false === $res_count ) {
  390. throw new LapaEngineException('Синтаксическая ошибка в строке %s', $this->template_line);
  391. }else if ( 0 == $res_count ) {
  392. return ;
  393. }
  394. if (!isset($match[0])) {
  395. throw new LapaEngineException('Синтаксическая ошибка в строке %s', $this->template_line);
  396. }else {
  397. $tags = & $match[0];
  398. }
  399. $count_tags = count($tags);
  400. for ( $index = 0; $count_tags > $index; ++$index ) {
  401. if (' ' == $tags[$index]) {
  402. continue;
  403. }
  404. $tag_index = strtolower($tags[$index]);
  405. if ( "\n" == $tag_index){
  406. $tokens[] = array(LT_NEW_LINE, $this->template_line += 1);
  407. $new_line = true;
  408. continue;
  409. }
  410. if ($new_line ) {
  411. if ( key_exists($tag_index, $this->known_tags) ) {
  412. $tokens[] = & $this->known_tags[$tag_index];
  413. $new_line = false;
  414. continue;
  415. }
  416. }
  417. $new_line = false;
  418. if ( key_exists($tag_index, $this->known_tags_operator) ) {
  419. //var_dump($tag_index);
  420. $tokens[] = & $this->known_tags_operator[$tag_index];
  421. continue;
  422. }
  423. switch ($tag_index) {
  424. case '$':
  425. if ( $count_tags == ($index += 1) ) {
  426. throw new LapaEngineException('Ошибка определения переменной в строке %s', $this->template_line);
  427. }
  428. $var_name = & $tags[$index];
  429. if ( !preg_match('!^[A-Za-z_]+[0-9]*$!', $var_name) ) {
  430. throw new LapaEngineException('Ошибка определения переменной в строке %s', $this->template_line);
  431. }
  432. if ( strtolower($var_name) == 'lapa' ) {
  433. $tokens[] = & $this->known_tags['lapa'];
  434. }else {
  435. $tokens[] = array(LT_VARIABLE, "\$_var['$var_name']");
  436. }
  437. unset($var_name);
  438. break;
  439. case '$$':
  440. if ( $count_tags == ($index += 1) ) {
  441. throw new LapaEngineException('Ошибка определения переменной в строке %s', $this->template_line);
  442. }
  443. $var_name = & $tags[$index];
  444. if ( !preg_match('!^[A-Za-z_]+[0-9]*$!', $var_name) ) {
  445. throw new LapaEngineException('Ошибка определения переменной в строке %s', $this->template_line);
  446. }
  447. $tokens[] = array(LT_VARIABLE, "\$_var_local['$var_name']");
  448. unset($var_name);
  449. break;
  450. case '//':
  451. for ( ++$index; $count_tags > $index; ++$index ) {
  452. if ( "\n" == $tags[$index] ) {
  453. $tokens[] = array(LT_NEW_LINE, $this->template_line +=1);
  454. $new_line = true;
  455. break;
  456. }
  457. }
  458. break;
  459. case '/*':
  460. for ( ++$index; $count_tags > $index; ++$index ) {
  461. if ( "*/" == $tags[$index] ) {
  462. break;
  463. }else if ("\n" == $tags[$index] ) {
  464. $tokens[] = array(LT_NEW_LINE, $this->template_line +=1);
  465. }
  466. }
  467. break;
  468. case '*': // комментарий, если начинается с новой строки
  469. $token = end($tokens);
  470. if ( 0 == $index || LT_NEW_LINE == $token[0] ) {
  471. for ( ++$index; $count_tags > $index; ++$index ) {
  472. if ( '*' == $tags[$index] ) {
  473. break;
  474. }else if ( "\n" == $tags[$index] ) {
  475. $tokens[] = array(LT_NEW_LINE, $this->template_line +=1);
  476. $new_line = true;
  477. break;
  478. }
  479. }
  480. }else {
  481. $tokens[] = & $this->known_tags2['*'];
  482. }
  483. break;
  484. case '..': // пропустим все пробелы и возможно все переводы строки
  485. for ( ++$index; $count_tags > $index; ++$index ) {
  486. if ( ' ' == $tags[$index] ) {
  487. continue;
  488. }else if ( "\n" == $tags[$index] ) {
  489. $tokens[] = array(LT_NEW_LINE, $this->template_line +=1);
  490. }else {
  491. --$index;
  492. break;
  493. }
  494. }
  495. $tokens[] = & $this->known_tags2['..'];
  496. break;
  497. case '#':
  498. if ( $count_tags == ($index += 1) ) {
  499. throw new LapaEngineException('Ошибка определения конфигурационной переменной в строке %s', $this->template_line);
  500. }
  501. $var_name = $tags[$index];
  502. if ( !preg_match('!^[A-Za-z_]+[0-9]*$!', $var_name) ) {
  503. throw new LapaEngineException('Ошибка определения конфигурационной переменной в строке %s', $this->template_line);
  504. }
  505. $tokens[] = & $this->known_tags['lapa'];
  506. $tokens[] = & $this->known_tags['.'];
  507. $tokens[] = array(LT_OTHER, 'config');
  508. $tokens[] = & $this->known_tags['.'];
  509. $tokens[] = array(LT_OTHER, $var_name);
  510. // для совместимости
  511. if ( $count_tags > ($index += 1) ) {
  512. if ($tags[$index] != '#') {
  513. $index -= 1;
  514. }
  515. }
  516. unset($var_name);
  517. break;
  518. case '/':
  519. $token = end($tokens);
  520. // если первый, или после \n считаем закрывающим блоком
  521. if ( 0 == $index || LT_NEW_LINE == $token[0] ) {
  522. if ( $count_tags == ($index += 1) ) {
  523. throw new LapaEngineException('Ошибка закрытия условного блока в строке %s', $this->template_line);
  524. }
  525. $tag = & $tags[$index];
  526. $tag_index = strtolower($tag);
  527. if ( !preg_match('!^[A-Za-z_]+[0-9]*$!', $tag) ) {
  528. throw new LapaEngineException('Ошибка определения блока в строке %s', $this->template_line);
  529. }
  530. if (key_exists($tag_index, $this->known_end_tags) ) {
  531. // известный тег
  532. $tokens[] = & $this->known_end_tags[$tag_index];
  533. }else {
  534. $tokens[] = array(LT_END);
  535. $tokens[] = array(LT_END_FUNCTION, $tag);
  536. }
  537. unset($tag);
  538. }else {
  539. $tokens[] = & $this->known_tags2['/'];
  540. }
  541. break;
  542. case '(':
  543. $token = end($tokens);
  544. // работает только для функций
  545. if ( LT_OTHER == $token[0] ) {
  546. array_pop($tokens);
  547. $tokens[] = array(LT_FUNCTION, $token[1]);
  548. }else {
  549. }
  550. $tokens[] = & $this->known_tags2['('];
  551. break;
  552. case '\'':
  553. $try_s = 0; $buff = '\''; $res = false;
  554. for ( ++$index; $count_tags > $index; ++$index ) {
  555. if ('\'' == $tags[$index]) {
  556. if ( !$try_s ) {
  557. $res = true;
  558. break;
  559. }
  560. }else if ("\n" == $tags[$index]) {
  561. $this->template_line += 1;
  562. }else if ("\\" == $tags[$index] ) {
  563. $try_s = (1 == $try_s) ? 0: ++$try_s;
  564. $buff .= $tags[$index];
  565. continue;
  566. }
  567. $try_s = 0;
  568. $buff .= $tags[$index];
  569. }
  570. if ( !$res ) {
  571. throw new LapaEngineException('Незакрытые кавычки в строке %s', $this->template_line);
  572. }
  573. $tokens[] = array(LT_VALUE, $buff . '\'');
  574. unset($buff);
  575. break;
  576. /**
  577. * собираем строку, в будущем реализуем возможность распознавать управляющие конструкции
  578. */
  579. case '"':
  580. $try_s = 0; $buff = '';$res = false;
  581. for ( ++$index; $count_tags > $index; ++$index ) {
  582. if ('"' == $tags[$index]) {
  583. if ( 0 == $try_s ) {
  584. $res = true;
  585. break;
  586. }else {
  587. $buff = substr($buff, 0, strlen($buff) - 1);
  588. }
  589. }else if ("\n" == $tags[$index]) {
  590. $this->template_line += 1;
  591. }else if ('\\' == $tags[$index] ) {
  592. $try_s = (1 == $try_s) ? 0 : 1;
  593. $buff .= $tags[$index];
  594. continue;
  595. }else if ('\'' == $tags[$index]) {
  596. $buff .= '\\';
  597. }
  598. $try_s = 0;
  599. $buff .= $tags[$index];
  600. }
  601. if ( !$res ) {
  602. throw new LapaEngineException('Незакрытые кавычки в строке %s', $this->template_line);
  603. }
  604. $buff = '\'' . $buff . '\'';
  605. $tokens[] = array(LT_VALUE, $buff);
  606. unset($buff);
  607. break;
  608. /**
  609. * MyClass::Title
  610. */
  611. case '::':
  612. $token = & $tokens[count($tokens) - 1];
  613. if ( LT_OTHER == $token[0] ) {
  614. $token[0] = LT_CLASS_STATIC;
  615. }else {
  616. throw new LapaEngineException('Недопустимый символ :: в строке %s', $this->template_line);
  617. }
  618. unset($token);
  619. break;
  620. /**
  621. * is [not, !] div by, is [not, !] even [by], is [not, !] odd [by]
  622. */
  623. case 'is':
  624. $is_operator = '';
  625. for ( ++$index; $count_tags > $index; ++$index ) {
  626. if (' ' == $tags[$index]) {
  627. continue;
  628. }
  629. $tag_index = strtolower($tags[$index]);
  630. switch ($tag_index) {
  631. case '!':
  632. $is_operator .= 'not';
  633. break;
  634. case 'not': case 'div': case 'by': case 'even': case 'odd':
  635. $is_operator .= $tag_index;
  636. break;
  637. default:
  638. --$index;
  639. break 2;
  640. }
  641. }
  642. if ( key_exists($is_operator, $this->known_is_operator) ) {
  643. $tokens[] = & $this->known_is_operator[$is_operator];
  644. }else {
  645. throw new LapaEngineException('Синтаксическая ошибка оператора "IS" в строке %s', $this->template_line);
  646. }
  647. unset($is_operator);
  648. break;
  649. case 'literal':
  650. $literal_text = array_shift($this->literal_text);
  651. $this->template_line += substr_count($literal_text, "\n");
  652. $tokens[] = array(LAPA_INLINE_HTML, $literal_text, $this->template_line);
  653. $tokens[] = array(LT_NEW_LINE, $this->template_line);
  654. $new_line = true;
  655. unset($literal_text);
  656. break;
  657. case 'php':
  658. $php_text = array_shift($this->php_text);
  659. $this->template_line += substr_count($php_text, "\n");
  660. $tokens[] = array(LAPA_INLINE_HTML, '<?php ' . $php_text .'?>', $this->template_line);
  661. $tokens[] = array(LT_NEW_LINE, $this->template_line);
  662. $new_line = true;
  663. unset($php_text);
  664. break;
  665. case 'ldelim':
  666. $tokens[] = array(LT_VALUE, '\'' . $this->options['left_delimiter'] . '\'');
  667. break;
  668. case 'rdelim':
  669. $tokens[] = array(LT_VALUE, '\'' . $this->options['right_delimiter'] . '\'');
  670. break;
  671. /**
  672. * [not, !] div by, [not, !] even [by], [not, !] odd [by]
  673. */
  674. case 'div': case 'even': case 'odd':
  675. $is_operator = '';
  676. /*
  677. * Проверка последнего значения, если not, удалим
  678. * {$i not even by 2}
  679. */
  680. $token = end($tokens);
  681. if ( LT_OPERATOR3 == $token[0] && '!' == $token[1] ) {
  682. array_pop($tokens); // удалим последний элемент
  683. $is_operator = 'not';
  684. }
  685. $is_operator .= $tag_index;
  686. for ( ++$index; $count_tags > $index; ++$index ) {
  687. $tag_index_tmp = strtolower($tags[$index]);
  688. if (' ' == $tag_index_tmp) {
  689. continue;
  690. }else if ('by' == $tag_index_tmp ) {
  691. $is_operator .= $tag_index_tmp;
  692. break;
  693. }else{
  694. --$index;
  695. break;
  696. }
  697. }
  698. if ( key_exists($is_operator, $this->known_is_operator) ) {
  699. $tokens[] = & $this->known_is_operator[$is_operator];
  700. }else {
  701. throw new LapaEngineException('Синтаксическая ошибка оператора "%s" в строке %s', $tag_index, $this->template_line);
  702. }
  703. unset($is_operator); unset($tag_index_tmp);
  704. break;
  705. default:
  706. $other_tag = & $tags[$index];
  707. if ( preg_match('!^[A-Za-z_]+[0-9A-Za-z_]*$!', $other_tag) ) {
  708. $tokens[] = array(LT_OTHER, $other_tag);
  709. }else if ( preg_match('!^[\d]+$!', $other_tag) ) {
  710. $tokens[] = array(LT_VALUE, $other_tag);
  711. }else {
  712. throw new LapaEngineException('Недопустимая конструкция "%s" в строке %s', $other_tag, $this->template_line);
  713. }
  714. unset($other_tag);
  715. break;
  716. }
  717. }
  718. }
  719. }