<commit_before><?php
class Text_Wiki_Parse_Plugin extends Text_Wiki_Parse {
    
    
    /**
    * 
    * The regular expression used to find source text matching this
    * rule.
    * 
    * @access public
    * 
    * @var string
    * 
    */
    
    //var $regex = '/^({([A-Z]+?)\((.+)?\)})((.+)({\2}))?(\s|$)/Umsi';
    var $regex = '/^(?:{([A-Z]+?)\((.+)?\)})(?:(.+)(?:{\1}))(\s|$)/Umsi';
    
    
    /**
    * 
    * Generates a token entry for the matched text.  Token options are:
    * 
    * 'text' => The full matched text, not including the <code></code> tags.
    * 
    * @access public
    *
    * @param array &$matches The array of matches from parse().
    *
    * @return A delimited token number to be used as a placeholder in
    * the source text.
    *
    */
    
    function process(&$matches)
    {
        // are there additional attribute arguments?
        $args = trim($matches[2]);
        
        if ($args == '') {
            $options = array(
                'text' => $matches[3],
                'plugin' => $matches[1],
                'attr' => array()
            );
        } else {
        	// get the attributes...
        	//$attr = $this->getAttrs($args);
            foreach (explode(',', $args) as $part) {
                if (false !== ($eq = strpos($part, '=')) && $eq != strlen($part) - 1) {
                    $attr[substr($part, 0, $eq)] = substr($part, $eq + 1 + ($part[$eq + 1] == '>' ? 1 : 0));
                } else {
                    $attr[$part] = '';
                }
            }
        	
        	// retain the options
            $options = array(
                'text' => $matches[3],
                'plugin' => $matches[1],
                'attr' => $attr
            );
        }
        
        return $this->wiki->addToken($this->rule, $options) . $matches[4];<commit_msg>Nested recursive plugins everywhere<commit_after><?php
class Text_Wiki_Parse_Plugin extends Text_Wiki_Parse {

    /**
     * Configurations keys, the script's name of the plugin will be prefixed and an extension added
     * the path is a comma separated list of directories where to find it
     *
     * @access public
     * @var string
     */
    var $conf = array (
    	'file_prefix' => 'wikiplugin_',
    	'file_extension' => '.php',
    	'file_path' => 'lib/wiki-plugins/'
    );

    /**
     * The regular expression used in second stage to find plugin's arguments
     *
     * @access public
     * @var string
     */
    var $regexArgs =  '#(\w+?)=>?("[^"]+"|\'[^\']+\'|[^"\'][^,]+)#';

    /**
    *
    * The regular expression used to find source text matching this
    * rule.
    *
    * @access public
    *
    * @var string
    *
    */

    //var $regex = '/^({([A-Z]+?)\((.+)?\)})((.+)({\2}))?(\s|$)/Umsi';
    var $regex = '/\{([A-Z]+?)\((.*?)\)}((?:(?R)|.)*?)\{\1}/msi';


    /**
    *
    * Generates a token entry for the matched text.  Token options are:
    *
    * 'text' => The full matched text, not including the <code></code> tags.
    *
    * @access public
    *
    * @param array &$matches The array of matches from parse().
    *
    * @return A delimited token number to be used as a placeholder in
    * the source text.
    *
    */

    function process(&$matches)
    {
        $func = $this->getConf('file_prefix') . strtolower($matches[1]);
        if (!function_exists($func)) {
            $file = $func . $this->getConf('file_extension');
            $paths = explode(',', $this->getConf('file_path'));
            $found = false;
            foreach ($paths as $path) {
                if (file_exists($pathfile = trim($path) . DIRECTORY_SEPARATOR . $file)) {
                    require_once $pathfile;
                    break;
                }
            }
            if (!function_exists($func)) {
                return $matches[0];
            }
        }

        // are there additional attribute arguments?
    	preg_match_all($this->regexArgs, $matches[2], $args, PREG_PATTERN_ORDER);
        $attr = array();
        foreach ($args[1] as $i=>$name) {
            if ($args[2][$i]{0} == '"' || $args[2][$i]{0} == "'") {
                $attr[$name] = substr($args[2][$i], 1, -1);
            } else {
                $attr[$name] = trim($args[2][$i]);
            }
        }

        // executes the plugin with data and pameters then recursive re-parse for nested or produced plugins
        $res = $func($matches[3], $attr);
        return preg_replace_callback(
                $this->regex,
                array(&$this, 'process'),
                $res
            );
{'fraction_non_alphanumeric': 0.18025657751685148, 'fraction_numerical': 0.006305718634485757, 'mean_word_length': 1.672864613596746, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 30, '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': '7307341', 'n_tokens_mistral': 1465, 'n_tokens_neox': 1399, 'n_words': 351}