PageRenderTime 25ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/include/vendors/h2o/h2o/parser.php

https://github.com/jouvent/Genitura
PHP | 283 lines | 249 code | 24 blank | 10 comment | 27 complexity | 2482986c51ad0da5e57cb4bfb24057a2 MD5 | raw file
  1. <?php
  2. class H2o_Lexer {
  3. function __construct($options = array()) {
  4. $this->options = $options;
  5. if ($this->options['TRIM_TAGS'])
  6. $trim = '(?:\r?\n)?';
  7. $this->pattern = ('/\G(.*?)(?:' .
  8. preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
  9. preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
  10. preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
  11. );
  12. }
  13. function tokenize($source) {
  14. $result = new TokenStream;
  15. $pos = 0;
  16. $matches = array();
  17. preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);
  18. foreach ($matches as $match) {
  19. if ($match[1])
  20. $result->feed('text', $match[1], $pos);
  21. $tagpos = $pos + strlen($match[1]);
  22. if ($match[2])
  23. $result->feed('block', trim($match[2]), $tagpos);
  24. elseif ($match[3])
  25. $result->feed('variable', trim($match[3]), $tagpos);
  26. elseif ($match[4])
  27. $result->feed('comment', trim($match[4]), $tagpos);
  28. $pos += strlen($match[0]);
  29. }
  30. if ($pos < strlen($source)){
  31. $result->feed('text', substr($source, $pos), $pos);
  32. }
  33. $result->close();
  34. return $result;
  35. }
  36. }
  37. class H2o_Parser {
  38. var $first;
  39. var $storage = array();
  40. var $filename;
  41. var $runtime;
  42. function __construct($source, $filename, $runtime, $options) {
  43. $this->options = $options;
  44. //$this->source = $source;
  45. $this->runtime = $runtime;
  46. $this->filename = $filename;
  47. $this->first = true;
  48. $this->lexer = new H2o_Lexer($options);
  49. $this->tokenstream = $this->lexer->tokenize($source);
  50. $this->storage = array(
  51. 'blocks' => array(),
  52. 'templates' => array(),
  53. 'included' => array()
  54. );
  55. }
  56. function &parse() {
  57. $until = func_get_args();
  58. $nodelist = new NodeList($this);
  59. while($token = $this->tokenstream->next()) {
  60. //$token = $this->tokenstream->current();
  61. switch($token->type) {
  62. case 'text' :
  63. $node = new TextNode($token->content, $token->position);
  64. break;
  65. case 'variable' :
  66. $args = H2o_Parser::parseArguments($token->content, $token->position);
  67. $variable = array_shift($args);
  68. $filters = $args;
  69. $node = new VariableNode($variable, $filters, $token->position);
  70. break;
  71. case 'comment' :
  72. $node = new CommentNode($token->content);
  73. break;
  74. case 'block' :
  75. if (in_array($token->content, $until)) {
  76. $this->token = $token;
  77. return $nodelist;
  78. }
  79. @list($name, $args) = preg_split('/\s+/',$token->content, 2);
  80. $node = H2o::createTag($name, $args, $this, $token->position);
  81. $this->token = $token;
  82. }
  83. $this->searching = join(',',$until);
  84. $this->first = false;
  85. $nodelist->append($node);
  86. }
  87. if ($until) {
  88. throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
  89. }
  90. return $nodelist;
  91. }
  92. function skipTo($until) {
  93. $this->parse($until);
  94. return null;
  95. }
  96. # Parse arguments
  97. static function parseArguments($source = null, $fpos = 0){
  98. $parser = new ArgumentLexer($source, $fpos);
  99. $result = array();
  100. $current_buffer = &$result;
  101. $filter_buffer = array();
  102. $tokens = $parser->parse();
  103. foreach ($tokens as $token) {
  104. list($token, $data) = $token;
  105. if ($token == 'filter_start') {
  106. $filter_buffer = array();
  107. $current_buffer = &$filter_buffer;
  108. }
  109. elseif ($token == 'filter_end') {
  110. if (count($filter_buffer))
  111. $result[] = $filter_buffer;
  112. $current_buffer = &$result;
  113. }
  114. elseif ($token == 'boolean') {
  115. $current_buffer[] = ($data === 'true'? true : false);
  116. }
  117. elseif ($token == 'name') {
  118. $current_buffer[] = symbol($data);
  119. }
  120. elseif ($token == 'number' || $token == 'string') {
  121. $current_buffer[] = $data;
  122. }
  123. elseif ($token == 'named_argument') {
  124. $last = $current_buffer[count($current_buffer) - 1];
  125. if (!is_array($last))
  126. $current_buffer[] = array();
  127. $namedArgs =& $current_buffer[count($current_buffer) - 1];
  128. list($name,$value) = array_map('trim', explode(':', $data, 2));
  129. # if argument value is variable mark it
  130. $value = self::parseArguments($value);
  131. $namedArgs[$name] = $value[0];
  132. }
  133. elseif( $token == 'operator') {
  134. $current_buffer[] = array('operator'=>$data);
  135. }
  136. }
  137. return $result;
  138. }
  139. }
  140. class H2O_RE {
  141. static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number, $string, $i18n_string, $name, $named_args;
  142. function init() {
  143. $r = 'strip_regex';
  144. self::$whitespace = '/\s+/m';
  145. self::$parentheses = '/\(|\)/m';
  146. self::$filter_end = '/;/';
  147. self::$boolean = '/true|false/';
  148. self::$seperator = '/,/';
  149. self::$pipe = '/\|/';
  150. self::$operator = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
  151. self::$number = '/\d+(\.\d*)?/';
  152. self::$name = '/[a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
  153. self::$string = '/(?:
  154. "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | # Double Quote string
  155. \'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
  156. )/xsm';
  157. self::$i18n_string = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";
  158. self::$named_args = "{
  159. ({$r(self::$name)})(?:{$r(self::$whitespace)})?
  160. :
  161. (?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
  162. }x";
  163. }
  164. }
  165. H2O_RE::init();
  166. class ArgumentLexer {
  167. private $source;
  168. private $match;
  169. private $pos = 0, $fpos, $eos;
  170. private $operator_map = array(
  171. '!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
  172. );
  173. function __construct($source, $fpos = 0){
  174. if (!is_null($source))
  175. $this->source = $source;
  176. $this->fpos=$fpos;
  177. }
  178. function parse(){
  179. $result = array();
  180. $filtering = false;
  181. while (!$this->eos()) {
  182. $this->scan(H2O_RE::$whitespace);
  183. if (!$filtering) {
  184. if ($this->scan(H2O_RE::$operator)){
  185. $operator = trim($this->match);
  186. if(isset($this->operator_map[$operator]))
  187. $operator = $this->operator_map[$operator];
  188. $result[] = array('operator', $operator);
  189. }
  190. elseif ($this->scan(H2O_RE::$boolean))
  191. $result[] = array('boolean', $this->match);
  192. elseif ($this->scan(H2O_RE::$named_args))
  193. $result[] = array('named_argument', $this->match);
  194. elseif ($this->scan(H2O_RE::$name))
  195. $result[] = array('name', $this->match);
  196. elseif ($this->scan(H2O_RE::$pipe)) {
  197. $filtering = true;
  198. $result[] = array('filter_start', $this->match);
  199. }
  200. elseif ($this->scan(H2O_RE::$seperator))
  201. $result[] = array('separator', null);
  202. elseif ($this->scan(H2O_RE::$i18n_string))
  203. $result[] = array('string', $this->match);
  204. elseif ($this->scan(H2O_RE::$number))
  205. $result[] = array('number', $this->match);
  206. else
  207. throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
  208. }
  209. else {
  210. // parse filters, with chaining and ";" as filter end character
  211. if ($this->scan(H2O_RE::$pipe)) {
  212. $result[] = array('filter_end', null);
  213. $result[] = array('filter_start', null);
  214. }
  215. elseif ($this->scan(H2O_RE::$seperator))
  216. $result[] = array('separator', null);
  217. elseif ($this->scan(H2O_RE::$filter_end)) {
  218. $result[] = array('filter_end', null);
  219. $filtering = false;
  220. }
  221. elseif ($this->scan(H2O_RE::$boolean))
  222. $result[] = array('boolean', $this->match);
  223. elseif ($this->scan(H2O_RE::$named_args))
  224. $result[] = array('named_argument', $this->match);
  225. elseif ($this->scan(H2O_RE::$name))
  226. $result[] = array('name', $this->match);
  227. elseif ($this->scan(H2O_RE::$i18n_string))
  228. $result[] = array('string', $this->match);
  229. elseif ($this->scan(H2O_RE::$number))
  230. $result[] = array('number', $this->match);
  231. else
  232. throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
  233. }
  234. }
  235. // if we are still in the filter state, we add a filter_end token.
  236. if ($filtering)
  237. $result[] = array('filter_end', null);
  238. return $result;
  239. }
  240. # String scanner
  241. function scan($regexp) {
  242. if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
  243. $this->match = $match[0];
  244. $this->pos += strlen($this->match);
  245. return true;
  246. }
  247. return false;
  248. }
  249. function eos() {
  250. return $this->pos >= strlen($this->source);
  251. }
  252. /**
  253. * return the position in the template
  254. */
  255. function getPosition() {
  256. return $this->fpos + $this->pos;
  257. }
  258. }
  259. ?>