<commit_before><?php
namespace Plitz\Bindings\Blitz;

use Plitz\Parser\Expression;
use Plitz\Parser\Expressions;

class JsCompiler extends \Plitz\Compilers\JsCompiler
{
    use EscapeExpressionTrait;
    use ResolveIncludeTrait;
    use ResolveParentVariableTrait;

    private $basePath;

    public function __construct($stream, $basePath)
    {
        parent::__construct($stream);

        $this->basePath = $basePath;
    }

    public function printBlock(Expression $value)
    {
        if ($value instanceof Expressions\MethodCall && $value->getMethodName() === 'assignVar') {
            $this->codeEmitter->lineNoEnding($this->currentContext . '[');
            $this->expression($value->getArguments()[0]);
            $this->codeEmitter->raw('] = ');
            $this->expression($value->getArguments()[1]);
            $this->codeEmitter->raw(';')->newline();
            return;<commit_msg>Wrap expression in helpers.isEmpty() call if necessary<commit_after><?php
namespace Plitz\Bindings\Blitz;

use Plitz\Parser\Expression;
use Plitz\Parser\Expressions;

class JsCompiler extends \Plitz\Compilers\JsCompiler
{
    use EscapeExpressionTrait;
    use ResolveIncludeTrait;
    use ResolveParentVariableTrait;

    private $basePath;

    public function __construct($stream, $basePath)
    {
        parent::__construct($stream);

        $this->basePath = $basePath;
    }

    /**
     * Helper function which returns true if the expression requires boolean input values
     *
     * @param Expression $expr
     * @return bool
     */
    protected static function expressionRequiresBooleanInput(Expression $expr)
    {
        return (
            ($expr instanceof Expressions\Binary && in_array($expr->getOperation(), [Expressions\Binary::OPERATOR_AND, Expressions\Binary::OPERATOR_OR])) ||
            ($expr instanceof Expressions\Unary && $expr->getOperation() === Expressions\Unary::OPERATION_NOT)
        );
    }

    /**
     * Wraps the expression in a `helpers.isEmpty()` call, if necessary
     *
     * @param Expression $expr
     * @return Expression
     */
    protected function wrapExpressionInIsEmptyCall(Expression $expr)
    {
        if ($expr instanceof Expressions\Binary) {
            $shouldWrap = self::expressionRequiresBooleanInput($expr);

            // check left and right sub-expressions
            $left = ($shouldWrap || self::expressionRequiresBooleanInput($expr->getLeft()))
                ? $this->wrapExpressionInIsEmptyCall($expr->getLeft())
                : $expr->getLeft();
            $right = ($shouldWrap || self::expressionRequiresBooleanInput($expr->getRight()))
                ? $this->wrapExpressionInIsEmptyCall($expr->getRight())
                : $expr->getRight();

            if ($left !== $expr->getLeft() || $right !== $expr->getRight()) {
                $expr = new Expressions\Binary($left, $right, $expr->getOperation());
            }
        } else if ($expr instanceof Expressions\Unary) {
            $shouldWrap = self::expressionRequiresBooleanInput($expr);

            // check sub-expression
            $subExpr = ($shouldWrap || self::expressionRequiresBooleanInput($expr->getExpression()))
                ? $this->wrapExpressionInIsEmptyCall($expr->getExpression())
                : $expr->getExpression();

            if ($subExpr !== $expr->getExpression()) {
                $expr = new Expressions\Unary($subExpr, $expr->getOperation());

                // check if we have a double nested unary not operator
                if (
                    $expr->getOperation() === Expressions\Unary::OPERATION_NOT &&
                    $expr->getExpression() instanceof Expressions\Unary &&
                    $expr->getExpression()->getOperation() === Expressions\Unary::OPERATION_NOT
                ) {
                    // unwrap the nested expression
                    $expr = $expr->getExpression()->getExpression();
                }
            }
        } else if ($expr instanceof Expressions\Scalar) {
            // can be calculated at build-time
            $isEmpty = empty($expr->getValue());
            $expr = new Expressions\Scalar($isEmpty);
        } else if (
            ($expr instanceof Expressions\GetAttribute) ||
            ($expr instanceof Expressions\MethodCall) ||
            ($expr instanceof Expressions\Variable)
        ) {
            // wrap potential empty value in a `!helpers.isEmpty($)` call
            $expr = new Expressions\Unary(
                new Expressions\MethodCall(
                    'isEmpty',
                    [$expr]
                ),
                Expressions\Unary::OPERATION_NOT
            );
        }

        return $expr;
    }

    public function ifBlock(Expression $condition)
    {
        $condition = $this->wrapExpressionInIsEmptyCall($condition);

        parent::ifBlock($condition);
    }

    public function elseIfBlock(Expression $condition)
    {
        $condition = $this->wrapExpressionInIsEmptyCall($condition);

        parent::elseIfBlock($condition);
    }

    public function printBlock(Expression $value)
    {
        if ($value instanceof Expressions\MethodCall && $value->getMethodName() === 'assignVar') {
            $this->codeEmitter->lineNoEnding($this->currentContext . '[');
            $this->expression($value->getArguments()[0]);
            $this->codeEmitter->raw('] = ');
            $this->expression($value->getArguments()[1]);
            $this->codeEmitter->raw(';')->newline();
            return;
{'fraction_non_alphanumeric': 0.13112678603725808, 'fraction_numerical': 0.0007234581298607343, 'mean_word_length': 2.3617021276595747, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 59, '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': '2343451', 'n_tokens_mistral': 1434, 'n_tokens_neox': 1398, 'n_words': 275}