You are here

protected function JSqueeze::makeVars in Minify JS 7

1 call to JSqueeze::makeVars()
JSqueeze::squeeze in lib/JSqueeze.php
Squeezes a JavaScript source code.

File

lib/JSqueeze.php, line 618

Class

JSqueeze

Code

protected function makeVars($closure, &$tree, $key) {
  $tree['code'] =& $closure;
  $tree['nfe'] = false;
  $tree['used'] = array();
  $tree['local'] = array();

  // Replace multiple "var" declarations by a single one
  $closure = preg_replace_callback("'(?<=[\n\\{\\}])var [^\n\\{\\};]+(?:\nvar [^\n\\{\\};]+)+'", array(
    $this,
    'mergeVarDeclarations',
  ), $closure);

  // Get all local vars (functions, arguments and "var" prefixed)
  $vars =& $tree['local'];
  if (preg_match("'^( [^(]*)?\\((.*?)\\)\\{'", $closure, $v)) {
    if ($v[1]) {
      $vars[$tree['nfe'] = substr($v[1], 1)] = -1;
      $tree['parent']['local'][';' . $key] =& $vars[$tree['nfe']];
    }
    if ($v[2]) {
      $i = 0;
      $v = explode(',', $v[2]);
      foreach ($v as $w) {
        $vars[$w] = $this->argFreq[$i++] - 1;

        // Give a bonus to argument variables
      }
    }
  }
  $v = preg_split("'(?<![\$.a-zA-Z0-9_])var '", $closure);
  if ($i = count($v) - 1) {
    $w = array();
    while ($i) {
      $j = $c = 0;
      $l = strlen($v[$i]);
      while ($j < $l) {
        switch ($v[$i][$j]) {
          case '(':
          case '[':
          case '{':
            ++$c;
            break;
          case ')':
          case ']':
          case '}':
            if ($c-- <= 0) {
              break 2;
            }
            break;
          case ';':
          case "\n":
            if (!$c) {
              break 2;
            }
          default:
            $c || ($w[] = $v[$i][$j]);
        }
        ++$j;
      }
      $w[] = ',';
      --$i;
    }
    $v = explode(',', implode('', $w));
    foreach ($v as $w) {
      if (preg_match("'^{$this->varRx}'", $w, $v)) {
        isset($vars[$v[0]]) || ($vars[$v[0]] = 0);
      }
    }
  }
  if (preg_match_all("@function ({$this->varRx})//''\"\"#@", $closure, $v)) {
    foreach ($v[1] as $w) {
      isset($vars[$w]) || ($vars[$w] = 0);
    }
  }
  if ($this->argFreq[-1] && preg_match_all("@}catch\\(({$this->varRx})@", $closure, $v)) {
    $v[0] = array();
    foreach ($v[1] as $w) {
      isset($v[0][$w]) ? ++$v[0][$w] : ($v[0][$w] = 1);
    }
    foreach ($v[0] as $w => $v) {
      $vars[$w] = $this->argFreq[-1] - $v;
    }
  }

  // Get all used vars, local and non-local
  $vars =& $tree['used'];
  if (preg_match_all("#([.,{]?(?:[gs]et )?)(?<![a-zA-Z0-9_\$])({$this->varRx})(:?)#", $closure, $w, PREG_SET_ORDER)) {
    foreach ($w as $k) {
      if (isset($k[1][0]) && (',' === $k[1][0] || '{' === $k[1][0])) {
        if (':' === $k[3]) {
          $k = '.' . $k[2];
        }
        elseif ('get ' === substr($k[1], 1, 4) || 'set ' === substr($k[1], 1, 4)) {
          ++$this->charFreq[ord($k[1][1])];

          // "g" or "s"
          ++$this->charFreq[101];

          // "e"
          ++$this->charFreq[116];

          // "t"
          $k = '.' . $k[2];
        }
        else {
          $k = $k[2];
        }
      }
      else {
        $k = $k[1] . $k[2];
      }
      isset($vars[$k]) ? ++$vars[$k] : ($vars[$k] = 1);
    }
  }
  if (preg_match_all("#//''\"\"[0-9]+(?:['!]|/')#", $closure, $w)) {
    foreach ($w[0] as $a) {
      $v = "'" === substr($a, -1) && "/'" !== substr($a, -2) && $this->specialVarRx ? preg_split("#([.,{]?(?:[gs]et )?(?<![a-zA-Z0-9_\$@]){$this->specialVarRx}:?)#", $this->strings[$a], -1, PREG_SPLIT_DELIM_CAPTURE) : array(
        $this->strings[$a],
      );
      $a = count($v);
      for ($i = 0; $i < $a; ++$i) {
        $k = $v[$i];
        if (1 === $i % 2) {
          if (',' === $k[0] || '{' === $k[0]) {
            if (':' === substr($k, -1)) {
              $k = '.' . substr($k, 1, -1);
            }
            elseif ('get ' === substr($k, 1, 4) || 'set ' === substr($k, 1, 4)) {
              ++$this->charFreq[ord($k[1])];

              // "g" or "s"
              ++$this->charFreq[101];

              // "e"
              ++$this->charFreq[116];

              // "t"
              $k = '.' . substr($k, 5);
            }
            else {
              $k = substr($k, 1);
            }
          }
          elseif (':' === substr($k, -1)) {
            $k = substr($k, 0, -1);
          }
          $w =& $tree;
          while (isset($w['parent']) && !(isset($w['used'][$k]) || isset($w['local'][$k]))) {
            $w =& $w['parent'];
          }
          (isset($w['used'][$k]) || isset($w['local'][$k])) && (isset($vars[$k]) ? ++$vars[$k] : ($vars[$k] = 1));
          unset($w);
        }
        if (0 === $i % 2 || !isset($vars[$k])) {
          foreach (count_chars($v[$i], 1) as $k => $w) {
            $this->charFreq[$k] += $w;
          }
        }
      }
    }
  }

  // Propagate the usage number to parents
  foreach ($vars as $w => $a) {
    $k =& $tree;
    $chain = array();
    do {
      $vars =& $k['local'];
      $chain[] =& $k;
      if (isset($vars[$w])) {
        unset($k['used'][$w]);
        if (isset($vars[$w])) {
          $vars[$w] += $a;
        }
        else {
          $vars[$w] = $a;
        }
        $a = false;
        break;
      }
    } while ($k['parent'] && ($k =& $k['parent']));
    if ($a && !$k['parent']) {
      if (isset($vars[$w])) {
        $vars[$w] += $a;
      }
      else {
        $vars[$w] = $a;
      }
    }
    if (isset($tree['used'][$w]) && isset($vars[$w])) {
      foreach ($chain as &$b) {
        isset($b['local'][$w]) || ($b['used'][$w] =& $vars[$w]);
      }
    }
  }

  // Analyse childs
  $tree['childs'] = array();
  $vars =& $tree['childs'];
  if (preg_match_all("@//''\"\"#[0-9]+'@", $closure, $w)) {
    foreach ($w[0] as $a) {
      $vars[$a] = array(
        'parent' => &$tree,
      );
      $this
        ->makeVars($this->closures[$a], $vars[$a], $a);
    }
  }
}