<commit_before><?php

/**
 * This file is part of the Ray.Aop package
 *
 * @package Ray.Aop
 * @license http://opensource.org/licenses/bsd-license.php BSD
 */
namespace Ray\Aop;

use PHPParser_BuilderFactory;
use PHPParser_Lexer;
use PHPParser_Parser;
use PHPParser_PrettyPrinter_Zend;
use PHPParser_PrettyPrinterAbstract;
use ReflectionClass;
use ReflectionMethod;
use TokenReflection\ReflectionParameter;

/**
 * This file is part of the Ray.Aop package
 *
 * @package Ray.Aop
 * @license http://opensource.org/licenses/bsd-license.php BSD
 */
final class Compiler implements CompilerInterface
{
    /**
     * @var \PHPParser_Parser
     */
    private $parser;

    /**
     * @var \PHPParser_BuilderFactory
     */
    private $factory;

    /**
     * @var string
     */
    private $classDir;

    /**
     * @param PHPParser_Parser                $parser
     * @param PHPParser_BuilderFactory        $factory
     * @param PHPParser_PrettyPrinterAbstract $printer
     * @param string                          $classDir
     */
    public function __construct(
        $classDir = null,
        PHPParser_Parser $parser = null,
        PHPParser_BuilderFactory $factory = null,
        PHPParser_PrettyPrinterAbstract $printer = null
    ) {
        ini_set('xdebug.max_nesting_level', 2000);
        $this->classDir = $classDir ? : sys_get_temp_dir();
        $this->parser = $parser ? : new PHPParser_Parser(new PHPParser_Lexer);
        $this->factory = $factory ? : new PHPParser_BuilderFactory;
        $this->printer = $printer ? : new PHPParser_PrettyPrinter_Zend;
    }

    /**
     * Return new aspect weaved object instance
     *
     * @param       $class
     * @param array $args
     * @param Bind  $bind
     *
     * @return object
     */
    public function newInstance($class, array $args = [], Bind $bind)
    {
        $class = $this->compile($class, $bind);
        $instance = (new ReflectionClass($class))->newInstanceArgs($args);
        $instance->___bind = $bind;

        return $instance;
    }

    /**
     * @param      $class
     * @param Bind $bind
     *
     * @return string
     */
    public function compile($class, Bind $bind)
    {
        $class = new ReflectionClass($class);
        $newClassName = $this->getClassName($class, $bind);
        if (class_exists($newClassName, false)) {
            return $newClassName;
        }
        $file = $this->classDir . "/{$newClassName}.php";
        $stmts = [
            $this->getClass($newClassName, $class, $bind)
                ->addStmts($this->getMethods($class, $bind))
                ->getNode()
        ];
        $code = $this->printer->prettyPrint($stmts);
        file_put_contents($file, '<?php ' . PHP_EOL . $code);
        include_once $file;

        return $newClassName;
    }

    /**
     * @param \ReflectionClass $class
     * @param Bind             $bind
     *
     * @return string
     */
    private function getClassName(\ReflectionClass $class, Bind $bind)
    {
        $className = str_replace('\\', '', $class->getName()) . 'RaY' . md5($bind);

        return $className;
    }

    /**
     * @param \ReflectionClass $class
     *
     * @return \PHPParser_Builder_Class
     */
    private function getClass($newClassName, \ReflectionClass $class, Bind $bind)
    {
        $parentClass = $class->name;
        $builder = $this->factory
            ->class($newClassName)
            ->extend($parentClass)
            ->implement('Ray\Aop\WeavedInterface')
            ->addStmt(
                $this->factory->property('___intercept')->makePrivate()->setDefault(true)
            )->addStmt(
                $this->factory->property('___bind')->makePublic()
            );

        return $builder;
    }

    /**
     * @param ReflectionClass $class
     * @param Bind            $bind
     *
     * @return array<commit_msg>change generative file name to easy pick up<commit_after><?php

/**
 * This file is part of the Ray.Aop package
 *
 * @package Ray.Aop
 * @license http://opensource.org/licenses/bsd-license.php BSD
 */
namespace Ray\Aop;

use PHPParser_BuilderFactory;
use PHPParser_Lexer;
use PHPParser_Parser;
use PHPParser_PrettyPrinter_Zend;
use PHPParser_PrettyPrinterAbstract;
use ReflectionClass;
use ReflectionMethod;
use TokenReflection\ReflectionParameter;

/**
 * This file is part of the Ray.Aop package
 *
 * @package Ray.Aop
 * @license http://opensource.org/licenses/bsd-license.php BSD
 */
final class Compiler implements CompilerInterface
{
    /**
     * @var \PHPParser_Parser
     */
    private $parser;

    /**
     * @var \PHPParser_BuilderFactory
     */
    private $factory;

    /**
     * @var string
     */
    private $classDir;

    /**
     * @param PHPParser_Parser                $parser
     * @param PHPParser_BuilderFactory        $factory
     * @param PHPParser_PrettyPrinterAbstract $printer
     * @param string                          $classDir
     */
    public function __construct(
        $classDir = null,
        PHPParser_Parser $parser = null,
        PHPParser_BuilderFactory $factory = null,
        PHPParser_PrettyPrinterAbstract $printer = null
    ) {
        ini_set('xdebug.max_nesting_level', 2000);
        $this->classDir = $classDir ? : sys_get_temp_dir();
        $this->parser = $parser ? : new PHPParser_Parser(new PHPParser_Lexer);
        $this->factory = $factory ? : new PHPParser_BuilderFactory;
        $this->printer = $printer ? : new PHPParser_PrettyPrinter_Zend;
    }

    /**
     * Return new aspect weaved object instance
     *
     * @param       $class
     * @param array $args
     * @param Bind  $bind
     *
     * @return object
     */
    public function newInstance($class, array $args = [], Bind $bind)
    {
        $class = $this->compile($class, $bind);
        $instance = (new ReflectionClass($class))->newInstanceArgs($args);
        $instance->___bind = $bind;

        return $instance;
    }

    /**
     * @param      $class
     * @param Bind $bind
     *
     * @return string
     */
    public function compile($class, Bind $bind)
    {
        $class = new ReflectionClass($class);
        $newClassName = $this->getClassName($class, $bind);
        if (class_exists($newClassName, false)) {
            return $newClassName;
        }
        $file = $this->classDir . "/{$newClassName}.php";
        $stmts = [
            $this->getClass($newClassName, $class, $bind)
                ->addStmts($this->getMethods($class, $bind))
                ->getNode()
        ];
        $code = $this->printer->prettyPrint($stmts);
        file_put_contents($file, '<?php ' . PHP_EOL . $code);
        include_once $file;

        return $newClassName;
    }

    /**
     * @param \ReflectionClass $class
     * @param Bind             $bind
     *
     * @return string
     */
    private function getClassName(\ReflectionClass $class, Bind $bind)
    {
        $className = str_replace('\\', '', $class->getName()) . 'Ray' . spl_object_hash($bind) . 'Aop';

        return $className;
    }

    /**
     * @param \ReflectionClass $class
     *
     * @return \PHPParser_Builder_Class
     */
    private function getClass($newClassName, \ReflectionClass $class, Bind $bind)
    {
        $parentClass = $class->name;
        $builder = $this->factory
            ->class($newClassName)
            ->extend($parentClass)
            ->implement('Ray\Aop\WeavedInterface')
            ->addStmt(
                $this->factory->property('___intercept')->makePrivate()->setDefault(true)
            )->addStmt(
                $this->factory->property('___bind')->makePublic()
            );

        return $builder;
    }

    /**
     * @param ReflectionClass $class
     * @param Bind            $bind
     *
     * @return array
{'fraction_non_alphanumeric': 0.12894534257120863, 'fraction_numerical': 0.0011547344110854503, 'mean_word_length': 2.1597081475476285, 'pattern_counts': {'":': 0, '<': 7, '<?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': '205934', 'n_tokens_mistral': 2325, 'n_tokens_neox': 2303, 'n_words': 479}