/Translation/Scanner/Php/Parser/TokenStack.php

https://github.com/ad2joe/RosettaBundle · PHP · 224 lines · 101 code · 34 blank · 89 comment · 13 complexity · bcd888121f63aa704dc41b86053fba41 MD5 · raw file

  1. <?php
  2. namespace BeSimple\RosettaBundle\Translation\Scanner\Php\Parser;
  3. /**
  4. * @author: Jean-François Simon <contact@jfsimon.fr>
  5. */
  6. class TokenStack
  7. {
  8. /**
  9. * @var array
  10. */
  11. private $tokens;
  12. /**
  13. * @var array
  14. */
  15. private $ignore;
  16. /**
  17. * @var array
  18. */
  19. private $delimiters;
  20. /**
  21. * @var int
  22. */
  23. private $cursor;
  24. /**
  25. * Constructor.
  26. *
  27. * @param Token[] $tokens
  28. * @param array $ignore
  29. * @param array $delimiters
  30. */
  31. public function __construct(array $tokens = array(), array $ignore = array(T_WHITESPACE, T_BAD_CHARACTER, T_COMMENT, T_DOC_COMMENT), array $delimiters = array('(' => ')', '[' => ']', '{' => '}'))
  32. {
  33. $this->ignore = $ignore;
  34. $this->tokens = $tokens;
  35. $this->delimiters = $delimiters;
  36. $this->cursor = 0;
  37. }
  38. /**
  39. * Gets token for given index.
  40. * If index is negative, start by the end.
  41. *
  42. * @param int $index
  43. * @return Token|null
  44. */
  45. public function get($index)
  46. {
  47. if ($index < 0) {
  48. $index = count($this->tokens) + $index;
  49. }
  50. return isset($this->tokens[$index]) ? $this->tokens[$index] : null;
  51. }
  52. /**
  53. * Sets token by index.
  54. *
  55. * @param int $index
  56. * @param Token|array|string $token
  57. * @return TokenStack
  58. */
  59. public function set($index, $token)
  60. {
  61. $this->tokens[$index] = $token instanceof Token ? $token : new Token($token);
  62. return $this;
  63. }
  64. /**
  65. * Returns current cursor position.
  66. *
  67. * @return int
  68. */
  69. public function cursor()
  70. {
  71. return $this->cursor - 1;
  72. }
  73. /**
  74. * Reset cursor position.
  75. *
  76. * @return TokenStack
  77. */
  78. public function rewind()
  79. {
  80. $this->cursor = 0;
  81. return $this;
  82. }
  83. /**
  84. * Fetch next token.
  85. *
  86. * @return Token|null A Token instance, null if there is no more token
  87. */
  88. public function next()
  89. {
  90. if (isset($this->tokens[$this->cursor])) {
  91. return $this->tokens[$this->cursor ++];
  92. }
  93. return null;
  94. }
  95. /**
  96. * Append a token to the stack.
  97. *
  98. * @param array|string|Token $token
  99. *
  100. * @return TokenStack
  101. */
  102. public function push($token)
  103. {
  104. if (!$token instanceof Token) {
  105. $token = new Token($token);
  106. }
  107. if (!in_array($token->getType(), $this->ignore)) {
  108. $this->tokens[] = $token;
  109. }
  110. return $this;
  111. }
  112. /**
  113. * Returns number of tokens.
  114. *
  115. * @return int
  116. */
  117. public function count()
  118. {
  119. return count($this->tokens);
  120. }
  121. /**
  122. * Shift tokens from the stack.
  123. *
  124. * @param int $length
  125. *
  126. * @return TokenStack
  127. */
  128. public function shift($length = 1)
  129. {
  130. $shiftedTokens = array_slice($this->tokens, 0, $length);
  131. $this->tokens = array_slice($this->tokens, $length);
  132. return new TokenStack($shiftedTokens, $this->ignore, $this->delimiters);
  133. }
  134. /**
  135. * Pops tokens from the stack.
  136. *
  137. * @param int $length
  138. *
  139. * @return TokenStack
  140. */
  141. public function pop($length = 1)
  142. {
  143. $newCount = count($this->tokens) - $length;
  144. $poppedTokens = array_slice($this->tokens, $newCount, $length);
  145. $this->tokens = array_slice($this->tokens, 0, $newCount);
  146. return new TokenStack($poppedTokens, $this->ignore, $this->delimiters);
  147. }
  148. /**
  149. * Extract next tokens from the stack until given token is found.
  150. *
  151. * @param Token $until
  152. *
  153. * @return TokenStack
  154. */
  155. public function extract(Token $until, $keepLast = false)
  156. {
  157. $index = $this->cursor();
  158. $open = array();
  159. while (isset($this->tokens[$index])) {
  160. if (isset($this->delimiters[$this->tokens[$index]->getContent()])) {
  161. array_unshift($open, $this->tokens[$index]->getContent());
  162. }
  163. if (count($open) && $this->delimiters[$open[0]] === $this->tokens[$index]->getContent()) {
  164. array_shift($open);
  165. }
  166. $matchType = is_null($until->getType()) || $until->getType() === $this->tokens[$index]->getType();
  167. $matchContent = is_null($until->getContent()) || $until->getContent() === $this->tokens[$index]->getContent();
  168. if (count($open) === 0 && $matchType && $matchContent) {
  169. break;
  170. }
  171. $index ++;
  172. }
  173. $length = $keepLast ? $index - $this->cursor() + 1 : $index - $this->cursor();
  174. return new TokenStack(array_slice($this->tokens, $this->cursor(), $length), $this->ignore, $this->delimiters);
  175. }
  176. /**
  177. * Retrieve source code from tokens in the stack.
  178. *
  179. * @return string
  180. */
  181. public function source()
  182. {
  183. $contents = array();
  184. foreach ($this->tokens as $token)
  185. {
  186. $contents = $token->getContent();
  187. }
  188. return implode($contents, ' ');
  189. }
  190. }