<commit_before><?php

function hook_invoke($hook_name, &$arg) {
  global $hook_dispatcher;
  return $hook_dispatcher->$hook_name($arg);
}

function build_hook_dispatcher() {
  global $mod_infos;
  
  $ordered = array();
  $levels = array();
  
  foreach ($mod_infos as $mod => $info) {
    foreach ($info as $hook => $options) {
      $priority = $options['priority'];
      if (empty($ordered[$hook])) {
        $ordered[$hook] = array();
      }
      if (isset($ordered[$hook][$priority])) {
        die("duplicate priority $priority for hook $hook (guilty mod $mod, previous mod {$ordered[$hook][$priority]})");
      }
      $ordered[$hook][$priority] = array($mod, $options);
      $levels[$priority] = true;
    }
  }
  
  echo "Ordered mod map:\n";
  var_dump($ordered);
  
  $text = '';
  
  $text .= "class hook_dispatcher_base {\n";
  foreach (array_keys($ordered) as $hook) {
    $text .= "  function $hook(&\$args) {}\n";
  }
  $text .= "}\n";
  
  $sorted_levels = array_keys($levels);
  sort($sorted_levels);
  
  $prev_level = 'base';
  foreach ($sorted_levels as $level) {
    $text .= "class hook_dispatcher_$level extends hook_dispatcher_$prev_level {\n";
    foreach ($ordered as $hook => $mods) {
      foreach ($mods as $priority => $info) {
        list($mod, $options) = $info;
        if ($level == $priority) {
          $text .= "  public function $hook(&\$args) {\n";
          if (!isset($options['replace']) || !$options['replace']) {
            $text .= "    parent::$hook(\$args);\n";
          }
          $text .= "    ${mod}_$hook(\$args);\n";
          $text .= "  }\n";
        }
      }
    }
    $text .= "}\n";
    $prev_level = $level;
  }
  $text .= "class hook_dispatcher extends hook_dispatcher_$prev_level {\n";
  $text .= "}\n";
  
  echo "Generated dispatcher hierarchy:\n";
  echo $text;
  
  eval($text);
  global $hook_dispatcher;
  $hook_dispatcher = new hook_dispatcher;
}

$mod_infos = array();

$defined_hooks = array('shiny', 'useful');<commit_msg>Added an explanation for eval usage<commit_after><?php

function hook_invoke($hook_name, &$arg) {
  global $hook_dispatcher;
  return $hook_dispatcher->$hook_name($arg);
}

function build_hook_dispatcher() {
  global $mod_infos;
  
  $ordered = array();
  $levels = array();
  
  foreach ($mod_infos as $mod => $info) {
    foreach ($info as $hook => $options) {
      $priority = $options['priority'];
      if (empty($ordered[$hook])) {
        $ordered[$hook] = array();
      }
      if (isset($ordered[$hook][$priority])) {
        die("duplicate priority $priority for hook $hook (guilty mod $mod, previous mod {$ordered[$hook][$priority]})");
      }
      $ordered[$hook][$priority] = array($mod, $options);
      $levels[$priority] = true;
    }
  }
  
  echo "Ordered mod map:\n";
  var_dump($ordered);
  
  $text = '';
  
  $text .= "class hook_dispatcher_base {\n";
  foreach (array_keys($ordered) as $hook) {
    $text .= "  function $hook(&\$args) {}\n";
  }
  $text .= "}\n";
  
  $sorted_levels = array_keys($levels);
  sort($sorted_levels);
  
  $prev_level = 'base';
  foreach ($sorted_levels as $level) {
    $text .= "class hook_dispatcher_$level extends hook_dispatcher_$prev_level {\n";
    foreach ($ordered as $hook => $mods) {
      foreach ($mods as $priority => $info) {
        list($mod, $options) = $info;
        if ($level == $priority) {
          $text .= "  public function $hook(&\$args) {\n";
          if (!isset($options['replace']) || !$options['replace']) {
            $text .= "    parent::$hook(\$args);\n";
          }
          $text .= "    ${mod}_$hook(\$args);\n";
          $text .= "  }\n";
        }
      }
    }
    $text .= "}\n";
    $prev_level = $level;
  }
  $text .= "class hook_dispatcher extends hook_dispatcher_$prev_level {\n";
  $text .= "}\n";
  
  echo "Generated dispatcher hierarchy:\n";
  echo $text;
  
  // This eval call is supposed to be performed during mod installation,
  // with results saved into cache. In normal operation the cache file
  // would be included instead of running all preceding code in this function.
  eval($text);
  
  global $hook_dispatcher;
  $hook_dispatcher = new hook_dispatcher;
}

$mod_infos = array();

$defined_hooks = array('shiny', 'useful');
{'fraction_non_alphanumeric': 0.18397556390977443, 'fraction_numerical': 0.0, 'mean_word_length': 2.9126838235294117, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1258805', 'n_tokens_mistral': 1437, 'n_tokens_neox': 1423, 'n_words': 328}