<commit_before><?php
/******************************************************************************
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
 * 
 * Copyright (c) 2016 <NAME> <<EMAIL>>
 *
 * This software is licensed under The MIT License. You should have received 
 * a copy of the license along with the code.
 */

namespace Lechimp\Dicto\Graph;

class QueryImpl implements Query {
    /**
     * @var Graph
     */
    protected $graph;

    /**
     * @var array[]
     */
    protected $steps;

    public function __construct(Graph $graph) {
        $this->graph = $graph;
        $this->steps = [];
    }

    /**
     * Expand the entities currently matched by the query.
     *
     * @param   \Closure    $expander   Entity -> Entity[]
     * @return  Query
     */
    public function expand(\Closure $expander) {
        $clone = clone $this;
        $clone->steps[] = ["expand", $expander];
        assert('$this->steps != $clone->steps');
        return $clone;
    }

    /**
     * Extract information from the currently matched query.
     *
     * @param   \Closure    $extractor  Entity -> &Result -> null
     * @return  Query
     */
    public function extract(\Closure $extractor) {
        $clone = clone $this;
        $clone->steps[] = ["extract", $extractor];
        assert('$this->steps != $clone->steps');
        return $clone;
    }

    /**
     * Run the query. The current result will be cloned in every expansion.
     *
     * @param   mixed   $result
     * @return  mixed[]
     */
    public function run($result) {
        $nodes = $this->add_result($this->graph->nodes(), $result);

        foreach ($this->steps as $step) {
            list($cmd,$clsr) = $step;
            if ($cmd == "expand") {
                $new_nodes = [];
                foreach ($nodes as $r) {
                    list($node, $result) = $r;
                    $new_nodes[] = $this->add_result($clsr($node), $result);
                }
                $nodes = call_user_func_array("array_merge", $new_nodes);
            }
            elseif ($cmd == "extract") {
                foreach ($nodes as $i => $r) {
                    list($node, $result) = $r;
                    if (is_object($result)) {
                        $clsr($node, clone $result);
                    }
                    else {
                        $clsr($node, $result);
                    }
                    $nodes[$i][1] = $result;
                }
            }
            else {
                throw new \LogicException("Unknown command: $cmd");
            }
        }

        return array_values(array_map(function($r) {
            return $r[1];
        }, $nodes));
    }

    protected function add_result(array $nodes, &$result) {
        $res = [];
        foreach ($nodes as $node) {
            $res[] = [$node, $result];
        }
        return $res;
    }

    /**
     * @var \Closure[]
     */
    protected $filters = [];

    /**
     * Execute the query on a graph. Get a list of results of the
     * query with the nodes and relations establishing the path.
     *
     * @param   Graph   $graph
     * @return  PathCollection
     */
    public function execute_on(Graph $graph) {
        $num = count($this->filters);
        if ($num === 0) {
            return new PathCollection([]);
        }

        $collection = new PathCollection
            ( array_map(function($n) { return new Path($n); }
            , $graph->nodes()
            ));

        for ($i = 0; $i < $num - 1; $i++) {
            // early exit
            if ($collection->is_empty()) {
                return $collection;
            }

            $matcher = $this->filters[$i];
            $collection->extend(function(Path $p) use ($matcher) {
                $e = $p->last();
                if (!$matcher($e)) {
                    return [];
                }
                if ($e instanceof Node) {
                    return array_map(function(Relation $r) use ($p) {
                        $p2 = clone $p;
                        $p2->append($r);
                        return $p2;
                    }, $e->relations());
                }
                elseif ($e instanceof Relation) {
                    $p->append($e->target());
                    return [$p];
                }
                else {
                    throw new \LogicException("Unknown entity type: ".get_class($e));
                }
            });
        }
        $collection->filter_by_last_entity(end($this->filters));
        return $collection;
    }

    /**
     * Get a query with the given filter on the next entity.
     *
     * @param   \Closure    $filter  Entity -> bool
     * @param   Query
     */
    public function with_filter(\Closure $filter) {
        $clone = new _Query;
        $clone->filters = $this->filters;
        $clone->filters[] = $filter;
        assert('$this->filters != $clone->filters');
        return $clone;
    }
}<commit_msg>cleaned up QueryImpl<commit_after><?php
/******************************************************************************
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
 * 
 * Copyright (c) 2016 <NAME> <<EMAIL>>
 *
 * This software is licensed under The MIT License. You should have received 
 * a copy of the license along with the code.
 */

namespace Lechimp\Dicto\Graph;

class QueryImpl implements Query {
    /**
     * @var Graph
     */
    protected $graph;

    /**
     * @var array[]
     */
    protected $steps;

    public function __construct(Graph $graph) {
        $this->graph = $graph;
        $this->steps = [];
    }

    /**
     * Expand the entities currently matched by the query.
     *
     * @param   \Closure    $expander   Entity -> Entity[]
     * @return  Query
     */
    public function expand(\Closure $expander) {
        $clone = clone $this;
        $clone->steps[] = ["expand", $expander];
        assert('$this->steps != $clone->steps');
        return $clone;
    }

    /**
     * Extract information from the currently matched query.
     *
     * @param   \Closure    $extractor  Entity -> &Result -> null
     * @return  Query
     */
    public function extract(\Closure $extractor) {
        $clone = clone $this;
        $clone->steps[] = ["extract", $extractor];
        assert('$this->steps != $clone->steps');
        return $clone;
    }

    /**
     * Run the query. The current result will be cloned in every expansion.
     *
     * @param   mixed   $result
     * @return  mixed[]
     */
    public function run($result) {
        $nodes = $this->add_result($this->graph->nodes(), $result);

        foreach ($this->steps as $step) {
            list($cmd,$clsr) = $step;
            if ($cmd == "expand") {
                $nodes = $this->run_expand($nodes, $clsr);
            }
            elseif ($cmd == "extract") {
                $this->run_extract($nodes, $clsr);
            }
            else {
                throw new \LogicException("Unknown command: $cmd");
            }
        }

        return array_values(array_map(function($r) {
            return $r[1];
        }, $nodes));
    }

    protected function run_expand(array &$nodes, \Closure $clsr) {
        $new_nodes = [];
        foreach ($nodes as $r) {
            list($node, $result) = $r;
            $new_nodes[] = $this->add_result($clsr($node), $result);
        }
        return call_user_func_array("array_merge", $new_nodes);
    }

    protected function run_extract(array &$nodes, \Closure $clsr) {
        foreach ($nodes as $i => $r) {
            list($node, $result) = $r;
            if (is_object($result)) {
                $clsr($node, clone $result);
            }
            else {
                $clsr($node, $result);
            }
            $nodes[$i][1] = $result;
        }
    }


    protected function add_result(array $nodes, &$result) {
        $res = [];
        foreach ($nodes as $node) {
            $res[] = [$node, $result];
        }
        return $res;
    }
}
{'fraction_non_alphanumeric': 0.16044637321760694, 'fraction_numerical': 0.002231866088034718, 'mean_word_length': 1.576996805111821, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 63, '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': '5413667', 'n_tokens_mistral': 2325, 'n_tokens_neox': 2213, 'n_words': 576}