Tokens.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <?php
  2. /**
  3. * Token utilities.
  4. *
  5. * @package SqlParser
  6. * @subpackage Utils
  7. */
  8. namespace SqlParser\Utils;
  9. use SqlParser\Lexer;
  10. use SqlParser\Token;
  11. use SqlParser\TokensList;
  12. /**
  13. * Token utilities.
  14. *
  15. * @category Token
  16. * @package SqlParser
  17. * @subpackage Utils
  18. * @author Dan Ungureanu <udan1107@gmail.com>
  19. * @license http://opensource.org/licenses/GPL-2.0 GNU Public License
  20. */
  21. class Tokens
  22. {
  23. /**
  24. * Checks if a pattern is a match for the specified token.
  25. *
  26. * @param Token $token The token to be matched.
  27. * @param array $pattern The pattern to be matches.
  28. *
  29. * @return bool
  30. */
  31. public static function match(Token $token, array $pattern)
  32. {
  33. // Token.
  34. if ((isset($pattern['token']))
  35. && ($pattern['token'] !== $token->token)
  36. ) {
  37. return false;
  38. }
  39. // Value.
  40. if ((isset($pattern['value']))
  41. && ($pattern['value'] !== $token->value)
  42. ) {
  43. return false;
  44. }
  45. if ((isset($pattern['value_str']))
  46. && (strcasecmp($pattern['value_str'], $token->value))
  47. ) {
  48. return false;
  49. }
  50. // Type.
  51. if ((isset($pattern['type']))
  52. && ($pattern['type'] !== $token->type)
  53. ) {
  54. return false;
  55. }
  56. // Flags.
  57. if ((isset($pattern['flags']))
  58. && (($pattern['flags'] & $token->flags) === 0)
  59. ) {
  60. return false;
  61. }
  62. return true;
  63. }
  64. public static function replaceTokens($list, array $find, array $replace)
  65. {
  66. /**
  67. * Whether the first parameter is a list.
  68. *
  69. * @var bool
  70. */
  71. $isList = $list instanceof TokensList;
  72. // Parsing the tokens.
  73. if (!$isList) {
  74. $list = Lexer::getTokens($list);
  75. }
  76. /**
  77. * The list to be returned.
  78. *
  79. * @var array
  80. */
  81. $newList = array();
  82. /**
  83. * The length of the find pattern is calculated only once.
  84. *
  85. * @var int
  86. */
  87. $findCount = count($find);
  88. /**
  89. * The starting index of the pattern.
  90. *
  91. * @var int
  92. */
  93. $i = 0;
  94. while ($i < $list->count) {
  95. // A sequence may not start with a comment.
  96. if ($list->tokens[$i]->type === Token::TYPE_COMMENT) {
  97. $newList[] = $list->tokens[$i];
  98. ++$i;
  99. continue;
  100. }
  101. /**
  102. * The index used to parse `$list->tokens`.
  103. *
  104. * This index might be running faster than `$k` because some tokens
  105. * are skipped.
  106. *
  107. * @var int
  108. */
  109. $j = $i;
  110. /**
  111. * The index used to parse `$find`.
  112. *
  113. * This index might be running slower than `$j` because some tokens
  114. * are skipped.
  115. *
  116. * @var int
  117. */
  118. $k = 0;
  119. // Checking if the next tokens match the pattern described.
  120. while (($j < $list->count) && ($k < $findCount)) {
  121. // Comments are being skipped.
  122. if ($list->tokens[$j]->type === Token::TYPE_COMMENT) {
  123. ++$j;
  124. }
  125. if (!static::match($list->tokens[$j], $find[$k])) {
  126. // This token does not match the pattern.
  127. break;
  128. }
  129. // Going to next token and segment of find pattern.
  130. ++$j;
  131. ++$k;
  132. }
  133. // Checking if the sequence was found.
  134. if ($k === $findCount) {
  135. // Inserting new tokens.
  136. foreach ($replace as $token) {
  137. $newList[] = $token;
  138. }
  139. // Skipping next `$findCount` tokens.
  140. $i = $j;
  141. } else {
  142. // Adding the same token.
  143. $newList[] = $list->tokens[$i];
  144. ++$i;
  145. }
  146. }
  147. return $isList ?
  148. new TokensList($newList) : TokensList::build($newList);
  149. }
  150. }