<commit_before><?php

namespace Xport\Parser;

use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Xport\Parser\ParsingException;

/**
 * "foreach" expression executor
 *
 * @author <NAME> <<EMAIL>>
 */
class ForEachExecutor
{
    /**
     * @var ForEachParser
     */
    private $forEachParser;

    /**
     * @var PropertyAccessor
     */
    private $propertyAccessor;

    public function __construct()
    {
        $this->forEachParser = new ForEachParser();
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
    }

    /**
     * Executes a foreach expression.
     *
     * The expression has the form: 'foo as bar', where foo is an array and bar the value.
     *
     * @param string $expression foreach expression
     * @param scope $scope
     *
     * @throws ParsingException
     * @return Scope[]
     */
    public function execute($expression, Scope $scope)
    {
        $subScopes = [];

        $parseResult = $this->forEachParser->parse($expression);

        $resultArray = $this->parseFunction($parseResult['array']);
        if (is_array($resultArray)) {
            $function = $scope->getFunction($resultArray['functionName']);
            $array = $function($this->propertyAccessor->getValue($scope, $resultArray['parameter']));
        } else {
            $array = $this->propertyAccessor->getValue($scope, $parseResult['array']);
        }

        foreach ($array as $key => $value) {
            // New sub-scope
            $subScope = new Scope($scope);

            $resultValue = $this->parseFunction($parseResult['value']);
            if (is_array($resultValue)) {
                $function = $scope->getFunction($resultValue['functionName']);
                $subScope->bind($resultValue['parameter'], $function($value));
            } else {
                $subScope->bind($parseResult['value'], $value);
            }

            if (isset($parseResult['key'])) {
                $resultKey = $this->parseFunction($parseResult['key']);
                if (is_array($resultKey)) {
                    $function = $scope->getFunction($resultKey['functionName']);
                    $subScope->bind($resultKey['parameter'], $function($key));
                } else {
                    $subScope->bind($parseResult['key'], $key);
                }
            }

            $subScopes[] = $subScope;
        }

        return $subScopes;
    }

    /**
     * @param string $str
     * @return array|null Keys are 'array' and 'value'
     */
    private function parseFunction($str)
    {
        $result = preg_match('/^\s*([[:alnum:]]+)\(([[:alnum:]\.\[\]]+)\)\s*$/', $str, $matches);

        if ($result !== 1) {
            return null;
        }

        return [
            'functionName' => $matches[1],
            'parameter'    => $matches[2],
        ];
    }
}<commit_msg>Added todo<commit_after><?php

namespace Xport\Parser;

use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Xport\Parser\ParsingException;

/**
 * "foreach" expression executor
 *
 * @author <NAME> <<EMAIL>>
 */
class ForEachExecutor
{
    /**
     * @var ForEachParser
     */
    private $forEachParser;

    /**
     * @var PropertyAccessor
     */
    private $propertyAccessor;

    public function __construct()
    {
        $this->forEachParser = new ForEachParser();
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
    }

    /**
     * Executes a foreach expression.
     *
     * The expression has the form: 'foo as bar', where foo is an array and bar the value.
     *
     * @param string $expression foreach expression
     * @param scope $scope
     *
     * @throws ParsingException
     * @return Scope[]
     */
    public function execute($expression, Scope $scope)
    {
        $subScopes = [];

        $parseResult = $this->forEachParser->parse($expression);

        $resultArray = $this->parseFunction($parseResult['array']);
        if (is_array($resultArray)) {
            $function = $scope->getFunction($resultArray['functionName']);
            $array = $function($this->propertyAccessor->getValue($scope, $resultArray['parameter']));
        } else {
            $array = $this->propertyAccessor->getValue($scope, $parseResult['array']);
        }

        foreach ($array as $key => $value) {
            // New sub-scope
            $subScope = new Scope($scope);

            $resultValue = $this->parseFunction($parseResult['value']);
            if (is_array($resultValue)) {
                $function = $scope->getFunction($resultValue['functionName']);
                $subScope->bind($resultValue['parameter'], $function($value));
            } else {
                $subScope->bind($parseResult['value'], $value);
            }

            if (isset($parseResult['key'])) {
                $resultKey = $this->parseFunction($parseResult['key']);
                if (is_array($resultKey)) {
                    $function = $scope->getFunction($resultKey['functionName']);
                    $subScope->bind($resultKey['parameter'], $function($key));
                } else {
                    $subScope->bind($parseResult['key'], $key);
                }
            }

            $subScopes[] = $subScope;
        }

        return $subScopes;
    }

    /**
     * @param string $str
     * @return array|null Keys are 'array' and 'value'
     * @todo Move into ForEachParser
     */
    private function parseFunction($str)
    {
        $result = preg_match('/^\s*([[:alnum:]]+)\(([[:alnum:]\.\[\]]+)\)\s*$/', $str, $matches);

        if ($result !== 1) {
            return null;
        }

        return [
            'functionName' => $matches[1],
            'parameter'    => $matches[2],
        ];
    }
}
{'fraction_non_alphanumeric': 0.1563351498637602, 'fraction_numerical': 0.0010217983651226157, 'mean_word_length': 2.1507510729613735, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 51, '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': '7133263', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1569, 'n_words': 309}