<commit_before><?php
/**
 * This file is part of DomainSpecificQuery
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author <NAME> <<EMAIL>>
 */

namespace DSQ\Compiler\StringCompiler;


use DSQ\Compiler\TypeBasedCompiler;
use DSQ\Expression\BasicExpression;
use DSQ\Expression\BinaryExpression;
use DSQ\Expression\TreeExpression;

/**
 * Class StringCompiler
 *
 * This is a simple compiler that converts expression using a math-style infix notation
 *
 * @package DSQ\Compiler\StringCompiler
 */
class StringCompiler extends TypeBasedCompiler
{
    public function __construct()
    {
        $this
            ->registerTransformation(array($this, 'basicExpression'), '*', '*')
            ->registerTransformation(array($this, 'binaryExpression'), 'DSQ\Expression\BinaryExpression')
            ->registerTransformation(array($this, 'treeExpression'), 'DSQ\Expression\TreeExpression')
            ->registerTransformation(array($this, 'binaryExpressionWithNoSpaces'), 'DSQ\Expression\BinaryExpression', '^')
        ;
    }

    /**
     * @param TreeExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function treeExpression(TreeExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        $pieces = array();

        foreach ($expression->getChildren() as $child) {
            $piece = $this->wrapCompositeExpression($child, $compiler->compile($child));

            $pieces[] = $piece;
        }

        return implode(" $op ", $pieces);
    }

    /**
     * @param BinaryExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function binaryExpression(BinaryExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        return "{$compiler->compile($expression->getLeft(), $compiler)} $op {$compiler->compile($expression->getRight(), $compiler)}";
    }

    /**
     * @param BinaryExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function binaryExpressionWithNoSpaces(BinaryExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        return "{$compiler->compile($expression->getLeft(), $compiler)}$op{$compiler->compile($expression->getRight(), $compiler)}";
    }

    /**
     * @param BasicExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function basicExpression(BasicExpression $expression, StringCompiler $compiler)
    {
        $value = $this->phraseExpression($expression->getValue());

        return $value;
    }

    /**
     * @param $expression
     * @param $string
     * @return string
     */
    private function wrapCompositeExpression($expression, $string)
    {
        if ($expression instanceof TreeExpression)
            $string = "($string)";

        return $string;
    }<commit_msg>Improved StringCompiler with operator precedence<commit_after><?php
/**
 * This file is part of DomainSpecificQuery
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author <NAME> <<EMAIL>>
 */

namespace DSQ\Compiler\StringCompiler;


use DSQ\Compiler\TypeBasedCompiler;
use DSQ\Expression\BasicExpression;
use DSQ\Expression\BinaryExpression;
use DSQ\Expression\Expression;
use DSQ\Expression\TreeExpression;

/**
 * Class StringCompiler
 *
 * This is a simple compiler that converts expression using a math-style infix notation
 *
 * @package DSQ\Compiler\StringCompiler
 */
class StringCompiler extends TypeBasedCompiler
{
    private $opsWeights = array();

    public function __construct()
    {
        $this
            ->registerTransformation(array($this, 'basicExpression'), '*', '*')
            ->registerTransformation(array($this, 'binaryExpression'), 'DSQ\Expression\BinaryExpression')
            ->registerTransformation(array($this, 'treeExpression'), 'DSQ\Expression\TreeExpression')
            ->registerTransformation(array($this, 'binaryExpressionWithNoSpaces'), 'DSQ\Expression\BinaryExpression', '^')

            ->setOpWeight('^', 1100)
            ->setOpWeight('*', 1000)
            ->setOpWeight('/', 1000)
            ->setOpWeight('%', 1000)
            ->setOpWeight('+', 900)
            ->setOpWeight('-', 900)
            ->setOpWeight('=', 800)
            ->setOpWeight('!=', 800)
            ->setOpWeight('<=', 800)
            ->setOpWeight('>=', 800)
            ->setOpWeight('<', 800)
            ->setOpWeight('>', 800)
            ->setOpWeight('and', 700)
            ->setOpWeight('or', 700)
            ->setOpWeight('xor', 700)
        ;
    }

    /**
     * @param TreeExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function treeExpression(TreeExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        $pieces = array();

        foreach ($expression->getChildren() as $child) {
            $piece = $this->precedenceParenthesis($expression, $child, $compiler->compile($child));

            $pieces[] = $piece;
        }

        return implode(" $op ", $pieces);
    }

    /**
     * @param BinaryExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function binaryExpression(BinaryExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        return "{$compiler->compile($expression->getLeft(), $compiler)} $op {$compiler->compile($expression->getRight(), $compiler)}";
    }

    /**
     * @param BinaryExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function binaryExpressionWithNoSpaces(BinaryExpression $expression, StringCompiler $compiler)
    {
        $op = strtoupper($expression->getValue());
        return "{$compiler->compile($expression->getLeft(), $compiler)}$op{$compiler->compile($expression->getRight(), $compiler)}";
    }

    /**
     * @param BasicExpression $expression
     * @param StringCompiler $compiler
     * @return string
     */
    public function basicExpression(BasicExpression $expression, StringCompiler $compiler)
    {
        $value = $this->phraseExpression($expression->getValue());

        return $value;
    }

    /**
     * Set operator weight for managing precedences
     *
     * @param string $op
     * @param int $weight
     *
     * @return $this The current instance
     */
    public function setOpWeight($op, $weight)
    {
        $this->opsWeights[$op] = (int) $weight;

        return $this;
    }

    /**
     * Get operator weight
     *
     * @param $op
     * @return int
     */
    public function getOpWeight($op)
    {
        if (isset($this->opsWeights[$op]))
            return $this->opsWeights[$op];

        return 0;
    }

    /**
     * @param $expression
     * @param $string
     * @return string
     */
    private function precedenceParenthesis(Expression $parent, Expression $child, $string)
    {
        if (!$this->isAtomic($child) && $this->getOpWeight($parent->getValue()) >= $this->getOpWeight($child->getValue()))
            $string = "($string)";

        return $string;
    }

    private function isAtomic(Expression $expression)
    {
        return $expression instanceof BasicExpression && $expression->getType() == 'basic';
    }
{'fraction_non_alphanumeric': 0.1364588789942378, 'fraction_numerical': 0.006547930853850184, 'mean_word_length': 2.902401635155851, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 76, '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': '5211112', 'n_tokens_mistral': 2067, 'n_tokens_neox': 1966, 'n_words': 463}