[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Configurator/ -> RecursiveParser.php (source)

   1  <?php declare(strict_types=1);
   2  
   3  /**
   4  * @package   s9e\TextFormatter
   5  * @copyright Copyright (c) 2010-2021 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\TextFormatter\Configurator;
   9  
  10  use RuntimeException;
  11  use s9e\TextFormatter\Configurator\RecursiveParser\MatcherInterface;
  12  
  13  class RecursiveParser
  14  {
  15      /**
  16      * @var array Callback associated with each match name
  17      */
  18      protected $callbacks = [];
  19  
  20      /**
  21      * @var array Match names associated with each group
  22      */
  23      protected $groupMatches = [];
  24  
  25      /**
  26      * @var array Groups associated with each match name
  27      */
  28      protected $matchGroups = [];
  29  
  30      /**
  31      * @var string Regexp used to match input
  32      */
  33      protected $regexp;
  34  
  35      /**
  36      * Parse given string
  37      *
  38      * @param  string $str
  39      * @param  string $name Allowed match, either match name or group name (default: allow all)
  40      * @return mixed
  41      */
  42  	public function parse(string $str, string $name = '')
  43      {
  44          $regexp = $this->regexp;
  45          if ($name !== '')
  46          {
  47              $restrict = (isset($this->groupMatches[$name])) ? implode('|', $this->groupMatches[$name]) : $name;
  48              $regexp   = preg_replace('(\\(\\?<(?!(?:' . $restrict . '|\\w+\\d+)>))', '(*F)$0', $regexp);
  49          }
  50  
  51          preg_match($regexp, $str, $m);
  52          if (!isset($m['MARK']))
  53          {
  54              throw new RuntimeException('Cannot parse ' . var_export($str, true));
  55          }
  56  
  57          $name = $m['MARK'];
  58          $args = $this->getArguments($m, $name);
  59  
  60          return [
  61              'groups' => $this->matchGroups[$name] ?? [],
  62              'match'  => $name,
  63              'value'  => call_user_func_array($this->callbacks[$name], $args)
  64          ];
  65      }
  66  
  67      /**
  68      * Set the list of matchers used by this parser
  69      *
  70      * @param  MatcherInterface[]
  71      * @return void
  72      */
  73  	public function setMatchers(array $matchers): void
  74      {
  75          $matchRegexps       = [];
  76          $this->groupMatches = [];
  77          $this->matchGroups  = [];
  78          foreach ($this->getMatchersConfig($matchers) as $matchName => $matchConfig)
  79          {
  80              foreach ($matchConfig['groups'] as $group)
  81              {
  82                  $this->groupMatches[$group][] = $matchName;
  83              }
  84  
  85              $regexp = $matchConfig['regexp'];
  86              $regexp = $this->insertCaptureNames($matchName , $regexp);
  87              $regexp = str_replace(' ', '\\s*+', $regexp);
  88              $regexp = '(?<' . $matchName  . '>' . $regexp . ')(*:' . $matchName  . ')';
  89  
  90              $matchRegexps[]                = $regexp;
  91              $this->callbacks[$matchName]   = $matchConfig['callback'];
  92              $this->matchGroups[$matchName] = $matchConfig['groups'];
  93          }
  94  
  95          $groupRegexps = [];
  96          foreach ($this->groupMatches as $group => $names)
  97          {
  98              $groupRegexps[] = '(?<' . $group . '>(?&' . implode(')|(?&', $names) . '))';
  99          }
 100  
 101          $this->regexp = '((?(DEFINE)' . implode('', $groupRegexps). ')'
 102                        . '^(?:' . implode('|', $matchRegexps) . ')$)s';
 103      }
 104  
 105      /**
 106      * Get the list of arguments produced by a regexp's match
 107      *
 108      * @param  string[] $matches Regexp matches
 109      * @param  string   $name    Regexp name
 110      * @return string[]
 111      */
 112  	protected function getArguments(array $matches, string $name): array
 113      {
 114          $args = [];
 115          $i    = 0;
 116          while (isset($matches[$name . $i]))
 117          {
 118              $args[] = $matches[$name . $i];
 119              ++$i;
 120          }
 121  
 122          return $args;
 123      }
 124  
 125      /**
 126      * Collect, normalize, sort and return the config for all matchers
 127      *
 128      * @param  MatcherInterface[] $matchers
 129      * @return array
 130      */
 131  	protected function getMatchersConfig(array $matchers): array
 132      {
 133          $matchersConfig = [];
 134          foreach ($matchers as $matcher)
 135          {
 136              foreach ($matcher->getMatchers() as $matchName => $matchConfig)
 137              {
 138                  if (is_string($matchConfig))
 139                  {
 140                      $matchConfig = ['regexp' => $matchConfig];
 141                  }
 142                  $parts       = explode(':', $matchName);
 143                  $matchName   = array_pop($parts);
 144                  $matchConfig += [
 145                      'callback' => [$matcher, 'parse' . $matchName],
 146                      'groups'   => [],
 147                      'order'    => 0
 148                  ];
 149                  $matchConfig['name']   = $matchName;
 150                  $matchConfig['groups'] = array_unique(array_merge($matchConfig['groups'], $parts));
 151                  sort($matchConfig['groups']);
 152  
 153                  $matchersConfig[$matchName] = $matchConfig;
 154              }
 155          }
 156          uasort($matchersConfig, 'static::sortMatcherConfig');
 157  
 158          return $matchersConfig;
 159      }
 160  
 161      /**
 162      * Insert capture names into given regexp
 163      *
 164      * @param  string $name   Name of the regexp, used to name captures
 165      * @param  string $regexp Original regexp
 166      * @return string         Modified regexp
 167      */
 168  	protected function insertCaptureNames(string $name, string $regexp): string
 169      {
 170          $i = 0;
 171  
 172          return preg_replace_callback(
 173              '((?<!\\\\)\\((?!\\?))',
 174              function ($m) use (&$i, $name)
 175              {
 176                  return '(?<' . $name . $i++ . '>';
 177              },
 178              $regexp
 179          );
 180      }
 181  
 182      /**
 183      * Compare two matchers' config
 184      *
 185      * @param  array $a
 186      * @param  array $b
 187      * @return integer
 188      */
 189  	protected static function sortMatcherConfig(array $a, array $b): int
 190      {
 191          if ($a['order'] !== $b['order'])
 192          {
 193              return $a['order'] - $b['order'];
 194          }
 195  
 196          return strcmp($a['name'], $b['name']);
 197      }
 198  }


Generated: Thu Mar 24 21:31:15 2022 Cross-referenced by PHPXref 0.7.1