Вход Регистрация
Файл: vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php
Строк: 2072
<?php declare(strict_types=1);

namespace 
PhpParserPrettyPrinter;

use 
PhpParserNode;
use 
PhpParserNodeExpr;
use 
PhpParserNodeExprAssignOp;
use 
PhpParserNodeExprBinaryOp;
use 
PhpParserNodeExprCast;
use 
PhpParserNodeName;
use 
PhpParserNodeScalar;
use 
PhpParserNodeScalarMagicConst;
use 
PhpParserNodeStmt;
use 
PhpParserPrettyPrinterAbstract;

class 
Standard extends PrettyPrinterAbstract
{
    
// Special nodes

    
protected function pParam(NodeParam $node) {
        return 
$this->pAttrGroups($node->attrGroupstrue)
             . 
$this->pModifiers($node->flags)
             . (
$node->type $this->p($node->type) . ' ' '')
             . (
$node->byRef '&' '')
             . (
$node->variadic '...' '')
             . 
$this->p($node->var)
             . (
$node->default ' = ' $this->p($node->default) : '');
    }

    protected function 
pArg(NodeArg $node) {
        return (
$node->name $node->name->toString() . ': ' '')
             . (
$node->byRef '&' '') . ($node->unpack '...' '')
             . 
$this->p($node->value);
    }

    protected function 
pVariadicPlaceholder(NodeVariadicPlaceholder $node) {
        return 
'...';
    }

    protected function 
pConst(NodeConst_ $node) {
        return 
$node->name ' = ' $this->p($node->value);
    }

    protected function 
pNullableType(NodeNullableType $node) {
        return 
'?' $this->p($node->type);
    }

    protected function 
pUnionType(NodeUnionType $node) {
        
$types = [];
        foreach (
$node->types as $typeNode) {
            if (
$typeNode instanceof NodeIntersectionType) {
                
$types[] = '('$this->p($typeNode) . ')';
                continue;
            }
            
$types[] = $this->p($typeNode);
        }
        return 
implode('|'$types);
    }

    protected function 
pIntersectionType(NodeIntersectionType $node) {
        return 
$this->pImplode($node->types'&');
    }

    protected function 
pIdentifier(NodeIdentifier $node) {
        return 
$node->name;
    }

    protected function 
pVarLikeIdentifier(NodeVarLikeIdentifier $node) {
        return 
'$' $node->name;
    }

    protected function 
pAttribute(NodeAttribute $node) {
        return 
$this->p($node->name)
             . (
$node->args '(' $this->pCommaSeparated($node->args) . ')' '');
    }

    protected function 
pAttributeGroup(NodeAttributeGroup $node) {
        return 
'#[' $this->pCommaSeparated($node->attrs) . ']';
    }

    
// Names

    
protected function pName(Name $node) {
        return 
implode('\', $node->parts);
    }

    protected function pName_FullyQualified(NameFullyQualified $node) {
        return '
\' . implode('\', $node->parts);
    }

    protected function pName_Relative(NameRelative $node) {
        return '
namespace\' . implode('\', $node->parts);
    }

    // Magic Constants

    protected function pScalar_MagicConst_Class(MagicConstClass_ $node) {
        return '
__CLASS__';
    }

    protected function pScalar_MagicConst_Dir(MagicConstDir $node) {
        return '
__DIR__';
    }

    protected function pScalar_MagicConst_File(MagicConstFile $node) {
        return '
__FILE__';
    }

    protected function pScalar_MagicConst_Function(MagicConstFunction_ $node) {
        return '
__FUNCTION__';
    }

    protected function pScalar_MagicConst_Line(MagicConstLine $node) {
        return '
__LINE__';
    }

    protected function pScalar_MagicConst_Method(MagicConstMethod $node) {
        return '
__METHOD__';
    }

    protected function pScalar_MagicConst_Namespace(MagicConstNamespace_ $node) {
        return '
__NAMESPACE__';
    }

    protected function pScalar_MagicConst_Trait(MagicConstTrait_ $node) {
        return '
__TRAIT__';
    }

    // Scalars

    protected function pScalar_String(ScalarString_ $node) {
        $kind = $node->getAttribute('
kind', ScalarString_::KIND_SINGLE_QUOTED);
        switch ($kind) {
            case ScalarString_::KIND_NOWDOC:
                $label = $node->getAttribute('
docLabel');
                if ($label && !$this->containsEndLabel($node->value, $label)) {
                    if ($node->value === '') {
                        return "<<<'
$label'n$label" . $this->docStringEndToken;
                    }

                    return "<<<'
$label'n$node->valuen$label"
                         . $this->docStringEndToken;
                }
                /* break missing intentionally */
            case ScalarString_::KIND_SINGLE_QUOTED:
                return $this->pSingleQuotedString($node->value);
            case ScalarString_::KIND_HEREDOC:
                $label = $node->getAttribute('
docLabel');
                if ($label && !$this->containsEndLabel($node->value, $label)) {
                    if ($node->value === '') {
                        return "<<<$labeln$label" . $this->docStringEndToken;
                    }

                    $escaped = $this->escapeString($node->value, null);
                    return "<<<$labeln" . $escaped . "n$label"
                         . $this->docStringEndToken;
                }
            /* break missing intentionally */
            case ScalarString_::KIND_DOUBLE_QUOTED:
                return '"' . 
$this->escapeString($node->value, '"') . '"';
        }
        throw new Exception('Invalid string kind');
    }

    protected function pScalar_Encapsed(ScalarEncapsed 
$node) {
        if (
$node->getAttribute('kind') === ScalarString_::KIND_HEREDOC) {
            
$label = $node->getAttribute('docLabel');
            if (
$label && !$this->encapsedContainsEndLabel($node->parts$label)) {
                if (count(
$node->parts) === 1
                    && 
$node->parts[0] instanceof ScalarEncapsedStringPart
                    && 
$node->parts[0]->value === ''
                ) {
                    return "
<<<$labeln$label" . $this->docStringEndToken;
                }

                return "
<<<$labeln" . $this->pEncapsList($node->parts, null) . "n$label"
                     . 
$this->docStringEndToken;
            }
        }
        return '"' . $this->pEncapsList($node->parts, '"') . '"';
    }

    protected function pScalar_LNumber(ScalarLNumber $node) {
        if ($node->value === -PHP_INT_MAX-1) {
            // PHP_INT_MIN cannot be represented as a literal,
            // because the sign is not part of the literal
            return '
(-' . PHP_INT_MAX . '-1)';
        }

        $kind = $node->getAttribute('
kind', ScalarLNumber::KIND_DEC);
        if (ScalarLNumber::KIND_DEC === $kind) {
            return (string) $node->value;
        }

        if ($node->value < 0) {
            $sign = '
-';
            $str = (string) -$node->value;
        } else {
            $sign = '';
            $str = (string) $node->value;
        }
        switch ($kind) {
            case ScalarLNumber::KIND_BIN:
                return $sign . '
0b' . base_convert($str, 10, 2);
            case ScalarLNumber::KIND_OCT:
                return $sign . '
0' . base_convert($str, 10, 8);
            case ScalarLNumber::KIND_HEX:
                return $sign . '
0x' . base_convert($str, 10, 16);
        }
        throw new Exception('
Invalid number kind');
    }

    protected function pScalar_DNumber(ScalarDNumber $node) {
        if (!is_finite($node->value)) {
            if ($node->value === INF) {
                return '
INF';
            } elseif ($node->value === -INF) {
                return '
-INF';
            } else {
                return '
NAN';
            }
        }

        // Try to find a short full-precision representation
        $stringValue = sprintf('
%.16G', $node->value);
        if ($node->value !== (double) $stringValue) {
            $stringValue = sprintf('
%.17G', $node->value);
        }

        // %G is locale dependent and there exists no locale-independent alternative. We don'
t want
        
// mess with switching locales here, so let's assume that a comma is the only non-standard
        // decimal separator we may encounter...
        
$stringValue str_replace(',''.'$stringValue);

        
// ensure that number is really printed as float
        
return preg_match('/^-?[0-9]+$/'$stringValue) ? $stringValue '.0' $stringValue;
    }

    protected function 
pScalar_EncapsedStringPart(ScalarEncapsedStringPart $node) {
        throw new 
LogicException('Cannot directly print EncapsedStringPart');
    }

    
// Assignments

    
protected function pExpr_Assign(ExprAssign $node) {
        return 
$this->pInfixOp(ExprAssign::class, $node->var' = '$node->expr);
    }

    protected function 
pExpr_AssignRef(ExprAssignRef $node) {
        return 
$this->pInfixOp(ExprAssignRef::class, $node->var' =& '$node->expr);
    }

    protected function 
pExpr_AssignOp_Plus(AssignOpPlus $node) {
        return 
$this->pInfixOp(AssignOpPlus::class, $node->var' += '$node->expr);
    }

    protected function 
pExpr_AssignOp_Minus(AssignOpMinus $node) {
        return 
$this->pInfixOp(AssignOpMinus::class, $node->var' -= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Mul(AssignOpMul $node) {
        return 
$this->pInfixOp(AssignOpMul::class, $node->var' *= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Div(AssignOpDiv $node) {
        return 
$this->pInfixOp(AssignOpDiv::class, $node->var' /= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Concat(AssignOpConcat $node) {
        return 
$this->pInfixOp(AssignOpConcat::class, $node->var' .= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Mod(AssignOpMod $node) {
        return 
$this->pInfixOp(AssignOpMod::class, $node->var' %= '$node->expr);
    }

    protected function 
pExpr_AssignOp_BitwiseAnd(AssignOpBitwiseAnd $node) {
        return 
$this->pInfixOp(AssignOpBitwiseAnd::class, $node->var' &= '$node->expr);
    }

    protected function 
pExpr_AssignOp_BitwiseOr(AssignOpBitwiseOr $node) {
        return 
$this->pInfixOp(AssignOpBitwiseOr::class, $node->var' |= '$node->expr);
    }

    protected function 
pExpr_AssignOp_BitwiseXor(AssignOpBitwiseXor $node) {
        return 
$this->pInfixOp(AssignOpBitwiseXor::class, $node->var' ^= '$node->expr);
    }

    protected function 
pExpr_AssignOp_ShiftLeft(AssignOpShiftLeft $node) {
        return 
$this->pInfixOp(AssignOpShiftLeft::class, $node->var' <<= '$node->expr);
    }

    protected function 
pExpr_AssignOp_ShiftRight(AssignOpShiftRight $node) {
        return 
$this->pInfixOp(AssignOpShiftRight::class, $node->var' >>= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Pow(AssignOpPow $node) {
        return 
$this->pInfixOp(AssignOpPow::class, $node->var' **= '$node->expr);
    }

    protected function 
pExpr_AssignOp_Coalesce(AssignOpCoalesce $node) {
        return 
$this->pInfixOp(AssignOpCoalesce::class, $node->var' ??= '$node->expr);
    }

    
// Binary expressions

    
protected function pExpr_BinaryOp_Plus(BinaryOpPlus $node) {
        return 
$this->pInfixOp(BinaryOpPlus::class, $node->left' + '$node->right);
    }

    protected function 
pExpr_BinaryOp_Minus(BinaryOpMinus $node) {
        return 
$this->pInfixOp(BinaryOpMinus::class, $node->left' - '$node->right);
    }

    protected function 
pExpr_BinaryOp_Mul(BinaryOpMul $node) {
        return 
$this->pInfixOp(BinaryOpMul::class, $node->left' * '$node->right);
    }

    protected function 
pExpr_BinaryOp_Div(BinaryOpDiv $node) {
        return 
$this->pInfixOp(BinaryOpDiv::class, $node->left' / '$node->right);
    }

    protected function 
pExpr_BinaryOp_Concat(BinaryOpConcat $node) {
        return 
$this->pInfixOp(BinaryOpConcat::class, $node->left' . '$node->right);
    }

    protected function 
pExpr_BinaryOp_Mod(BinaryOpMod $node) {
        return 
$this->pInfixOp(BinaryOpMod::class, $node->left' % '$node->right);
    }

    protected function 
pExpr_BinaryOp_BooleanAnd(BinaryOpBooleanAnd $node) {
        return 
$this->pInfixOp(BinaryOpBooleanAnd::class, $node->left' && '$node->right);
    }

    protected function 
pExpr_BinaryOp_BooleanOr(BinaryOpBooleanOr $node) {
        return 
$this->pInfixOp(BinaryOpBooleanOr::class, $node->left' || '$node->right);
    }

    protected function 
pExpr_BinaryOp_BitwiseAnd(BinaryOpBitwiseAnd $node) {
        return 
$this->pInfixOp(BinaryOpBitwiseAnd::class, $node->left' & '$node->right);
    }

    protected function 
pExpr_BinaryOp_BitwiseOr(BinaryOpBitwiseOr $node) {
        return 
$this->pInfixOp(BinaryOpBitwiseOr::class, $node->left' | '$node->right);
    }

    protected function 
pExpr_BinaryOp_BitwiseXor(BinaryOpBitwiseXor $node) {
        return 
$this->pInfixOp(BinaryOpBitwiseXor::class, $node->left' ^ '$node->right);
    }

    protected function 
pExpr_BinaryOp_ShiftLeft(BinaryOpShiftLeft $node) {
        return 
$this->pInfixOp(BinaryOpShiftLeft::class, $node->left' << '$node->right);
    }

    protected function 
pExpr_BinaryOp_ShiftRight(BinaryOpShiftRight $node) {
        return 
$this->pInfixOp(BinaryOpShiftRight::class, $node->left' >> '$node->right);
    }

    protected function 
pExpr_BinaryOp_Pow(BinaryOpPow $node) {
        return 
$this->pInfixOp(BinaryOpPow::class, $node->left' ** '$node->right);
    }

    protected function 
pExpr_BinaryOp_LogicalAnd(BinaryOpLogicalAnd $node) {
        return 
$this->pInfixOp(BinaryOpLogicalAnd::class, $node->left' and '$node->right);
    }

    protected function 
pExpr_BinaryOp_LogicalOr(BinaryOpLogicalOr $node) {
        return 
$this->pInfixOp(BinaryOpLogicalOr::class, $node->left' or '$node->right);
    }

    protected function 
pExpr_BinaryOp_LogicalXor(BinaryOpLogicalXor $node) {
        return 
$this->pInfixOp(BinaryOpLogicalXor::class, $node->left' xor '$node->right);
    }

    protected function 
pExpr_BinaryOp_Equal(BinaryOpEqual $node) {
        return 
$this->pInfixOp(BinaryOpEqual::class, $node->left' == '$node->right);
    }

    protected function 
pExpr_BinaryOp_NotEqual(BinaryOpNotEqual $node) {
        return 
$this->pInfixOp(BinaryOpNotEqual::class, $node->left' != '$node->right);
    }

    protected function 
pExpr_BinaryOp_Identical(BinaryOpIdentical $node) {
        return 
$this->pInfixOp(BinaryOpIdentical::class, $node->left' === '$node->right);
    }

    protected function 
pExpr_BinaryOp_NotIdentical(BinaryOpNotIdentical $node) {
        return 
$this->pInfixOp(BinaryOpNotIdentical::class, $node->left' !== '$node->right);
    }

    protected function 
pExpr_BinaryOp_Spaceship(BinaryOpSpaceship $node) {
        return 
$this->pInfixOp(BinaryOpSpaceship::class, $node->left' <=> '$node->right);
    }

    protected function 
pExpr_BinaryOp_Greater(BinaryOpGreater $node) {
        return 
$this->pInfixOp(BinaryOpGreater::class, $node->left' > '$node->right);
    }

    protected function 
pExpr_BinaryOp_GreaterOrEqual(BinaryOpGreaterOrEqual $node) {
        return 
$this->pInfixOp(BinaryOpGreaterOrEqual::class, $node->left' >= '$node->right);
    }

    protected function 
pExpr_BinaryOp_Smaller(BinaryOpSmaller $node) {
        return 
$this->pInfixOp(BinaryOpSmaller::class, $node->left' < '$node->right);
    }

    protected function 
pExpr_BinaryOp_SmallerOrEqual(BinaryOpSmallerOrEqual $node) {
        return 
$this->pInfixOp(BinaryOpSmallerOrEqual::class, $node->left' <= '$node->right);
    }

    protected function 
pExpr_BinaryOp_Coalesce(BinaryOpCoalesce $node) {
        return 
$this->pInfixOp(BinaryOpCoalesce::class, $node->left' ?? '$node->right);
    }

    protected function 
pExpr_Instanceof(ExprInstanceof_ $node) {
        list(
$precedence$associativity) = $this->precedenceMap[ExprInstanceof_::class];
        return 
$this->pPrec($node->expr$precedence$associativity, -1)
             . 
' instanceof '
             
$this->pNewVariable($node->class);
    }

    
// Unary expressions

    
protected function pExpr_BooleanNot(ExprBooleanNot $node) {
        return 
$this->pPrefixOp(ExprBooleanNot::class, '!'$node->expr);
    }

    protected function 
pExpr_BitwiseNot(ExprBitwiseNot $node) {
        return 
$this->pPrefixOp(ExprBitwiseNot::class, '~'$node->expr);
    }

    protected function 
pExpr_UnaryMinus(ExprUnaryMinus $node) {
        if (
$node->expr instanceof ExprUnaryMinus || $node->expr instanceof ExprPreDec) {
            
// Enforce -(-$expr) instead of --$expr
            
return '-(' $this->p($node->expr) . ')';
        }
        return 
$this->pPrefixOp(ExprUnaryMinus::class, '-'$node->expr);
    }

    protected function 
pExpr_UnaryPlus(ExprUnaryPlus $node) {
        if (
$node->expr instanceof ExprUnaryPlus || $node->expr instanceof ExprPreInc) {
            
// Enforce +(+$expr) instead of ++$expr
            
return '+(' $this->p($node->expr) . ')';
        }
        return 
$this->pPrefixOp(ExprUnaryPlus::class, '+'$node->expr);
    }

    protected function 
pExpr_PreInc(ExprPreInc $node) {
        return 
$this->pPrefixOp(ExprPreInc::class, '++'$node->var);
    }

    protected function 
pExpr_PreDec(ExprPreDec $node) {
        return 
$this->pPrefixOp(ExprPreDec::class, '--'$node->var);
    }

    protected function 
pExpr_PostInc(ExprPostInc $node) {
        return 
$this->pPostfixOp(ExprPostInc::class, $node->var'++');
    }

    protected function 
pExpr_PostDec(ExprPostDec $node) {
        return 
$this->pPostfixOp(ExprPostDec::class, $node->var'--');
    }

    protected function 
pExpr_ErrorSuppress(ExprErrorSuppress $node) {
        return 
$this->pPrefixOp(ExprErrorSuppress::class, '@'$node->expr);
    }

    protected function 
pExpr_YieldFrom(ExprYieldFrom $node) {
        return 
$this->pPrefixOp(ExprYieldFrom::class, 'yield from '$node->expr);
    }

    protected function 
pExpr_Print(ExprPrint_ $node) {
        return 
$this->pPrefixOp(ExprPrint_::class, 'print '$node->expr);
    }

    
// Casts

    
protected function pExpr_Cast_Int(CastInt_ $node) {
        return 
$this->pPrefixOp(CastInt_::class, '(int) '$node->expr);
    }

    protected function 
pExpr_Cast_Double(CastDouble $node) {
        
$kind $node->getAttribute('kind'CastDouble::KIND_DOUBLE);
        if (
$kind === CastDouble::KIND_DOUBLE) {
            
$cast '(double)';
        } elseif (
$kind === CastDouble::KIND_FLOAT) {
            
$cast '(float)';
        } elseif (
$kind === CastDouble::KIND_REAL) {
            
$cast '(real)';
        }
        return 
$this->pPrefixOp(CastDouble::class, $cast ' '$node->expr);
    }

    protected function 
pExpr_Cast_String(CastString_ $node) {
        return 
$this->pPrefixOp(CastString_::class, '(string) '$node->expr);
    }

    protected function 
pExpr_Cast_Array(CastArray_ $node) {
        return 
$this->pPrefixOp(CastArray_::class, '(array) '$node->expr);
    }

    protected function 
pExpr_Cast_Object(CastObject_ $node) {
        return 
$this->pPrefixOp(CastObject_::class, '(object) '$node->expr);
    }

    protected function 
pExpr_Cast_Bool(CastBool_ $node) {
        return 
$this->pPrefixOp(CastBool_::class, '(bool) '$node->expr);
    }

    protected function 
pExpr_Cast_Unset(CastUnset_ $node) {
        return 
$this->pPrefixOp(CastUnset_::class, '(unset) '$node->expr);
    }

    
// Function calls and similar constructs

    
protected function pExpr_FuncCall(ExprFuncCall $node) {
        return 
$this->pCallLhs($node->name)
             . 
'(' $this->pMaybeMultiline($node->args) . ')';
    }

    protected function 
pExpr_MethodCall(ExprMethodCall $node) {
        return 
$this->pDereferenceLhs($node->var) . '->' $this->pObjectProperty($node->name)
             . 
'(' $this->pMaybeMultiline($node->args) . ')';
    }

    protected function 
pExpr_NullsafeMethodCall(ExprNullsafeMethodCall $node) {
        return 
$this->pDereferenceLhs($node->var) . '?->' $this->pObjectProperty($node->name)
            . 
'(' $this->pMaybeMultiline($node->args) . ')';
    }

    protected function 
pExpr_StaticCall(ExprStaticCall $node) {
        return 
$this->pDereferenceLhs($node->class) . '::'
             
. ($node->name instanceof Expr
                
? ($node->name instanceof ExprVariable
                   
$this->p($node->name)
                   : 
'{' $this->p($node->name) . '}')
                : 
$node->name)
             . 
'(' $this->pMaybeMultiline($node->args) . ')';
    }

    protected function 
pExpr_Empty(ExprEmpty_ $node) {
        return 
'empty(' $this->p($node->expr) . ')';
    }

    protected function 
pExpr_Isset(ExprIsset_ $node) {
        return 
'isset(' $this->pCommaSeparated($node->vars) . ')';
    }

    protected function 
pExpr_Eval(ExprEval_ $node) {
        return 
'eval(' $this->p($node->expr) . ')';
    }

    protected function 
pExpr_Include(ExprInclude_ $node) {
        static 
$map = [
            
ExprInclude_::TYPE_INCLUDE      => 'include',
            
ExprInclude_::TYPE_INCLUDE_ONCE => 'include_once',
            
ExprInclude_::TYPE_REQUIRE      => 'require',
            
ExprInclude_::TYPE_REQUIRE_ONCE => 'require_once',
        ];

        return 
$map[$node->type] . ' ' $this->p($node->expr);
    }

    protected function 
pExpr_List(ExprList_ $node) {
        return 
'list(' $this->pCommaSeparated($node->items) . ')';
    }

    
// Other

    
protected function pExpr_Error(ExprError $node) {
        throw new 
LogicException('Cannot pretty-print AST with Error nodes');
    }

    protected function 
pExpr_Variable(ExprVariable $node) {
        if (
$node->name instanceof Expr) {
            return 
'${' $this->p($node->name) . '}';
        } else {
            return 
'$' $node->name;
        }
    }

    protected function 
pExpr_Array(ExprArray_ $node) {
        
$syntax $node->getAttribute('kind',
            
$this->options['shortArraySyntax'] ? ExprArray_::KIND_SHORT ExprArray_::KIND_LONG);
        if (
$syntax === ExprArray_::KIND_SHORT) {
            return 
'[' $this->pMaybeMultiline($node->itemstrue) . ']';
        } else {
            return 
'array(' $this->pMaybeMultiline($node->itemstrue) . ')';
        }
    }

    protected function 
pExpr_ArrayItem(ExprArrayItem $node) {
        return (
null !== $node->key $this->p($node->key) . ' => ' '')
             . (
$node->byRef '&' '')
             . (
$node->unpack '...' '')
             . 
$this->p($node->value);
    }

    protected function 
pExpr_ArrayDimFetch(ExprArrayDimFetch $node) {
        return 
$this->pDereferenceLhs($node->var)
             . 
'[' . (null !== $node->dim $this->p($node->dim) : '') . ']';
    }

    protected function 
pExpr_ConstFetch(ExprConstFetch $node) {
        return 
$this->p($node->name);
    }

    protected function 
pExpr_ClassConstFetch(ExprClassConstFetch $node) {
        return 
$this->pDereferenceLhs($node->class) . '::' $this->p($node->name);
    }

    protected function 
pExpr_PropertyFetch(ExprPropertyFetch $node) {
        return 
$this->pDereferenceLhs($node->var) . '->' $this->pObjectProperty($node->name);
    }

    protected function 
pExpr_NullsafePropertyFetch(ExprNullsafePropertyFetch $node) {
        return 
$this->pDereferenceLhs($node->var) . '?->' $this->pObjectProperty($node->name);
    }

    protected function 
pExpr_StaticPropertyFetch(ExprStaticPropertyFetch $node) {
        return 
$this->pDereferenceLhs($node->class) . '::$' $this->pObjectProperty($node->name);
    }

    protected function 
pExpr_ShellExec(ExprShellExec $node) {
        return 
'`' $this->pEncapsList($node->parts'`') . '`';
    }

    protected function 
pExpr_Closure(ExprClosure $node) {
        return 
$this->pAttrGroups($node->attrGroupstrue)
             . (
$node->static 'static ' '')
             . 
'function ' . ($node->byRef '&' '')
             . 
'(' $this->pCommaSeparated($node->params) . ')'
             
. (!empty($node->uses) ? ' use(' $this->pCommaSeparated($node->uses) . ')' '')
             . (
null !== $node->returnType ' : ' $this->p($node->returnType) : '')
             . 
' {' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pExpr_Match(ExprMatch_ $node) {
        return 
'match (' $this->p($node->cond) . ') {'
            
$this->pCommaSeparatedMultiline($node->armstrue)
            . 
$this->nl
            
'}';
    }

    protected function 
pMatchArm(NodeMatchArm $node) {
        return (
$node->conds $this->pCommaSeparated($node->conds) : 'default')
            . 
' => ' $this->p($node->body);
    }

    protected function 
pExpr_ArrowFunction(ExprArrowFunction $node) {
        return 
$this->pAttrGroups($node->attrGroupstrue)
            . (
$node->static 'static ' '')
            . 
'fn' . ($node->byRef '&' '')
            . 
'(' $this->pCommaSeparated($node->params) . ')'
            
. (null !== $node->returnType ': ' $this->p($node->returnType) : '')
            . 
' => '
            
$this->p($node->expr);
    }

    protected function 
pExpr_ClosureUse(ExprClosureUse $node) {
        return (
$node->byRef '&' '') . $this->p($node->var);
    }

    protected function 
pExpr_New(ExprNew_ $node) {
        if (
$node->class instanceof StmtClass_) {
            
$args $node->args '(' $this->pMaybeMultiline($node->args) . ')' '';
            return 
'new ' $this->pClassCommon($node->class$args);
        }
        return 
'new ' $this->pNewVariable($node->class)
            . 
'(' $this->pMaybeMultiline($node->args) . ')';
    }

    protected function 
pExpr_Clone(ExprClone_ $node) {
        return 
'clone ' $this->p($node->expr);
    }

    protected function 
pExpr_Ternary(ExprTernary $node) {
        
// a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.
        // this is okay because the part between ? and : never needs parentheses.
        
return $this->pInfixOp(ExprTernary::class,
            
$node->cond' ?' . (null !== $node->if ' ' $this->p($node->if) . ' ' '') . ': '$node->else
        
);
    }

    protected function 
pExpr_Exit(ExprExit_ $node) {
        
$kind $node->getAttribute('kind'ExprExit_::KIND_DIE);
        return (
$kind === ExprExit_::KIND_EXIT 'exit' 'die')
             . (
null !== $node->expr '(' $this->p($node->expr) . ')' '');
    }

    protected function 
pExpr_Throw(ExprThrow_ $node) {
        return 
'throw ' $this->p($node->expr);
    }

    protected function 
pExpr_Yield(ExprYield_ $node) {
        if (
$node->value === null) {
            return 
'yield';
        } else {
            
// this is a bit ugly, but currently there is no way to detect whether the parentheses are necessary
            
return '(yield '
                 
. ($node->key !== null $this->p($node->key) . ' => ' '')
                 . 
$this->p($node->value)
                 . 
')';
        }
    }

    
// Declarations

    
protected function pStmt_Namespace(StmtNamespace_ $node) {
        if (
$this->canUseSemicolonNamespaces) {
            return 
'namespace ' $this->p($node->name) . ';'
                 
$this->nl $this->pStmts($node->stmtsfalse);
        } else {
            return 
'namespace' . (null !== $node->name ' ' $this->p($node->name) : '')
                 . 
' {' $this->pStmts($node->stmts) . $this->nl '}';
        }
    }

    protected function 
pStmt_Use(StmtUse_ $node) {
        return 
'use ' $this->pUseType($node->type)
             . 
$this->pCommaSeparated($node->uses) . ';';
    }

    protected function 
pStmt_GroupUse(StmtGroupUse $node) {
        return 
'use ' $this->pUseType($node->type) . $this->pName($node->prefix)
             . 
'{' $this->pCommaSeparated($node->uses) . '};';
    }

    protected function 
pStmt_UseUse(StmtUseUse $node) {
        return 
$this->pUseType($node->type) . $this->p($node->name)
             . (
null !== $node->alias ' as ' $node->alias '');
    }

    protected function 
pUseType($type) {
        return 
$type === StmtUse_::TYPE_FUNCTION 'function '
            
: ($type === StmtUse_::TYPE_CONSTANT 'const ' '');
    }

    protected function 
pStmt_Interface(StmtInterface_ $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
'interface ' $node->name
             
. (!empty($node->extends) ? ' extends ' $this->pCommaSeparated($node->extends) : '')
             . 
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Enum(StmtEnum_ $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
'enum ' $node->name
             
. ($node->scalarType " : $node->scalarType'')
             . (!empty(
$node->implements) ? ' implements ' $this->pCommaSeparated($node->implements) : '')
             . 
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Class(StmtClass_ $node) {
        return 
$this->pClassCommon($node' ' $node->name);
    }

    protected function 
pStmt_Trait(StmtTrait_ $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
'trait ' $node->name
             
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_EnumCase(StmtEnumCase $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
'case ' $node->name
             
. ($node->expr ' = ' $this->p($node->expr) : '')
             . 
';';
    }

    protected function 
pStmt_TraitUse(StmtTraitUse $node) {
        return 
'use ' $this->pCommaSeparated($node->traits)
             . (empty(
$node->adaptations)
                ? 
';'
                
' {' $this->pStmts($node->adaptations) . $this->nl '}');
    }

    protected function 
pStmt_TraitUseAdaptation_Precedence(StmtTraitUseAdaptationPrecedence $node) {
        return 
$this->p($node->trait) . '::' $node->method
             
' insteadof ' $this->pCommaSeparated($node->insteadof) . ';';
    }

    protected function 
pStmt_TraitUseAdaptation_Alias(StmtTraitUseAdaptationAlias $node) {
        return (
null !== $node->trait $this->p($node->trait) . '::' '')
             . 
$node->method ' as'
             
. (null !== $node->newModifier ' ' rtrim($this->pModifiers($node->newModifier), ' ') : '')
             . (
null !== $node->newName     ' ' $node->newName                        '')
             . 
';';
    }

    protected function 
pStmt_Property(StmtProperty $node) {
        return 
$this->pAttrGroups($node->attrGroups)
            . (
=== $node->flags 'var ' $this->pModifiers($node->flags))
            . (
$node->type $this->p($node->type) . ' ' '')
            . 
$this->pCommaSeparated($node->props) . ';';
    }

    protected function 
pStmt_PropertyProperty(StmtPropertyProperty $node) {
        return 
'$' $node->name
             
. (null !== $node->default ' = ' $this->p($node->default) : '');
    }

    protected function 
pStmt_ClassMethod(StmtClassMethod $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
$this->pModifiers($node->flags)
             . 
'function ' . ($node->byRef '&' '') . $node->name
             
'(' $this->pMaybeMultiline($node->params) . ')'
             
. (null !== $node->returnType ' : ' $this->p($node->returnType) : '')
             . (
null !== $node->stmts
                
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}'
                
';');
    }

    protected function 
pStmt_ClassConst(StmtClassConst $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
$this->pModifiers($node->flags)
             . 
'const ' $this->pCommaSeparated($node->consts) . ';';
    }

    protected function 
pStmt_Function(StmtFunction_ $node) {
        return 
$this->pAttrGroups($node->attrGroups)
             . 
'function ' . ($node->byRef '&' '') . $node->name
             
'(' $this->pCommaSeparated($node->params) . ')'
             
. (null !== $node->returnType ' : ' $this->p($node->returnType) : '')
             . 
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Const(StmtConst_ $node) {
        return 
'const ' $this->pCommaSeparated($node->consts) . ';';
    }

    protected function 
pStmt_Declare(StmtDeclare_ $node) {
        return 
'declare (' $this->pCommaSeparated($node->declares) . ')'
             
. (null !== $node->stmts ' {' $this->pStmts($node->stmts) . $this->nl '}' ';');
    }

    protected function 
pStmt_DeclareDeclare(StmtDeclareDeclare $node) {
        return 
$node->key '=' $this->p($node->value);
    }

    
// Control flow

    
protected function pStmt_If(StmtIf_ $node) {
        return 
'if (' $this->p($node->cond) . ') {'
             
$this->pStmts($node->stmts) . $this->nl '}'
             
. ($node->elseifs ' ' $this->pImplode($node->elseifs' ') : '')
             . (
null !== $node->else ' ' $this->p($node->else) : '');
    }

    protected function 
pStmt_ElseIf(StmtElseIf_ $node) {
        return 
'elseif (' $this->p($node->cond) . ') {'
             
$this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Else(StmtElse_ $node) {
        return 
'else {' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_For(StmtFor_ $node) {
        return 
'for ('
             
$this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' '')
             . 
$this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' '')
             . 
$this->pCommaSeparated($node->loop)
             . 
') {' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Foreach(StmtForeach_ $node) {
        return 
'foreach (' $this->p($node->expr) . ' as '
             
. (null !== $node->keyVar $this->p($node->keyVar) . ' => ' '')
             . (
$node->byRef '&' '') . $this->p($node->valueVar) . ') {'
             
$this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_While(StmtWhile_ $node) {
        return 
'while (' $this->p($node->cond) . ') {'
             
$this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Do(StmtDo_ $node) {
        return 
'do {' $this->pStmts($node->stmts) . $this->nl
             
'} while (' $this->p($node->cond) . ');';
    }

    protected function 
pStmt_Switch(StmtSwitch_ $node) {
        return 
'switch (' $this->p($node->cond) . ') {'
             
$this->pStmts($node->cases) . $this->nl '}';
    }

    protected function 
pStmt_Case(StmtCase_ $node) {
        return (
null !== $node->cond 'case ' $this->p($node->cond) : 'default') . ':'
             
$this->pStmts($node->stmts);
    }

    protected function 
pStmt_TryCatch(StmtTryCatch $node) {
        return 
'try {' $this->pStmts($node->stmts) . $this->nl '}'
             
. ($node->catches ' ' $this->pImplode($node->catches' ') : '')
             . (
$node->finally !== null ' ' $this->p($node->finally) : '');
    }

    protected function 
pStmt_Catch(StmtCatch_ $node) {
        return 
'catch (' $this->pImplode($node->types'|')
             . (
$node->var !== null ' ' $this->p($node->var) : '')
             . 
') {' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Finally(StmtFinally_ $node) {
        return 
'finally {' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pStmt_Break(StmtBreak_ $node) {
        return 
'break' . ($node->num !== null ' ' $this->p($node->num) : '') . ';';
    }

    protected function 
pStmt_Continue(StmtContinue_ $node) {
        return 
'continue' . ($node->num !== null ' ' $this->p($node->num) : '') . ';';
    }

    protected function 
pStmt_Return(StmtReturn_ $node) {
        return 
'return' . (null !== $node->expr ' ' $this->p($node->expr) : '') . ';';
    }

    protected function 
pStmt_Throw(StmtThrow_ $node) {
        return 
'throw ' $this->p($node->expr) . ';';
    }

    protected function 
pStmt_Label(StmtLabel $node) {
        return 
$node->name ':';
    }

    protected function 
pStmt_Goto(StmtGoto_ $node) {
        return 
'goto ' $node->name ';';
    }

    
// Other

    
protected function pStmt_Expression(StmtExpression $node) {
        return 
$this->p($node->expr) . ';';
    }

    protected function 
pStmt_Echo(StmtEcho_ $node) {
        return 
'echo ' $this->pCommaSeparated($node->exprs) . ';';
    }

    protected function 
pStmt_Static(StmtStatic_ $node) {
        return 
'static ' $this->pCommaSeparated($node->vars) . ';';
    }

    protected function 
pStmt_Global(StmtGlobal_ $node) {
        return 
'global ' $this->pCommaSeparated($node->vars) . ';';
    }

    protected function 
pStmt_StaticVar(StmtStaticVar $node) {
        return 
$this->p($node->var)
             . (
null !== $node->default ' = ' $this->p($node->default) : '');
    }

    protected function 
pStmt_Unset(StmtUnset_ $node) {
        return 
'unset(' $this->pCommaSeparated($node->vars) . ');';
    }

    protected function 
pStmt_InlineHTML(StmtInlineHTML $node) {
        
$newline $node->getAttribute('hasLeadingNewline'true) ? "n" '';
        return 
'?>' $newline $node->value '<?php ';
    }

    protected function 
pStmt_HaltCompiler(StmtHaltCompiler $node) {
        return 
'__halt_compiler();' $node->remaining;
    }

    protected function 
pStmt_Nop(StmtNop $node) {
        return 
'';
    }

    
// Helpers

    
protected function pClassCommon(StmtClass_ $node$afterClassToken) {
        return 
$this->pAttrGroups($node->attrGroups$node->name === null)
            . 
$this->pModifiers($node->flags)
            . 
'class' $afterClassToken
            
. (null !== $node->extends ' extends ' $this->p($node->extends) : '')
            . (!empty(
$node->implements) ? ' implements ' $this->pCommaSeparated($node->implements) : '')
            . 
$this->nl '{' $this->pStmts($node->stmts) . $this->nl '}';
    }

    protected function 
pObjectProperty($node) {
        if (
$node instanceof Expr) {
            return 
'{' $this->p($node) . '}';
        } else {
            return 
$node;
        }
    }

    protected function 
pEncapsList(array $encapsList$quote) {
        
$return '';
        foreach (
$encapsList as $element) {
            if (
$element instanceof ScalarEncapsedStringPart) {
                
$return .= $this->escapeString($element->value$quote);
            } else {
                
$return .= '{' $this->p($element) . '}';
            }
        }

        return 
$return;
    }

    protected function 
pSingleQuotedString(string $string) {
        return 
''' . addcslashes($string, ''\') . ''';
    }

    protected function 
escapeString($string$quote) {
        if (
null === $quote) {
            
// For doc strings, don't escape newlines
            
$escaped addcslashes($string"tfv$\");
        } else {
            
$escaped = addcslashes($string, "nrtfv$" . $quote . "\");
        }

        // Escape control characters and non-UTF-8 characters.
        // Regex based on https://stackoverflow.com/a/11709412/385378.
        
$regex = '/(
              [x00-x08x0E-x1F] # Control characters
            | [xC0-xC1] # Invalid UTF-8 Bytes
            | [xF5-xFF] # Invalid UTF-8 Bytes
            | xE0(?=[x80-x9F]) # Overlong encoding of prior code point
            | xF0(?=[x80-x8F]) # Overlong encoding of prior code point
            | [xC2-xDF](?![x80-xBF]) # Invalid UTF-8 Sequence Start
            | [xE0-xEF](?![x80-xBF]{2}) # Invalid UTF-8 Sequence Start
            | [xF0-xF4](?![x80-xBF]{3}) # Invalid UTF-8 Sequence Start
            | (?<=[x00-x7FxF5-xFF])[x80-xBF] # Invalid UTF-8 Sequence Middle
            | (?<![xC2-xDF]|[xE0-xEF]|[xE0-xEF][x80-xBF]|[xF0-xF4]|[xF0-xF4][x80-xBF]|[xF0-xF4][x80-xBF]{2})[x80-xBF] # Overlong Sequence
            | (?<=[xE0-xEF])[x80-xBF](?![x80-xBF]) # Short 3 byte sequence
            | (?<=[xF0-xF4])[x80-xBF](?![x80-xBF]{2}) # Short 4 byte sequence
            | (?<=[xF0-xF4][x80-xBF])[x80-xBF](?![x80-xBF]) # Short 4 byte sequence (2)
        )/x';
        return preg_replace_callback(
$regex, function ($matches) {
            assert(strlen(
$matches[0]) === 1);
            
$hex = dechex(ord($matches[0]));;
            return '\x' . str_pad(
$hex, 2, '0', STR_PAD_LEFT);
        }, 
$escaped);
    }

    protected function containsEndLabel(
$string$label$atStart = true, $atEnd = true) {
        
$start = $atStart ? '(?:^|[rn])' : '[rn]';
        
$end = $atEnd ? '(?:$|[;rn])' : '[;rn]';
        return false !== strpos(
$string$label)
            && preg_match('/' . 
$start . $label . $end . '/', $string);
    }

    protected function encapsedContainsEndLabel(array 
$parts$label) {
        foreach (
$parts as $i => $part) {
            
$atStart = $i === 0;
            
$atEnd = $i === count($parts) - 1;
            if (
$part instanceof ScalarEncapsedStringPart
                && 
$this->containsEndLabel($part->value$label$atStart$atEnd)
            ) {
                return true;
            }
        }
        return false;
    }

    protected function pDereferenceLhs(Node 
$node) {
        if (!
$this->dereferenceLhsRequiresParens($node)) {
            return 
$this->p($node);
        } else  {
            return '(' . 
$this->p($node) . ')';
        }
    }

    protected function pCallLhs(Node 
$node) {
        if (!
$this->callLhsRequiresParens($node)) {
            return 
$this->p($node);
        } else  {
            return '(' . 
$this->p($node) . ')';
        }
    }

    protected function pNewVariable(Node 
$node) {
        // TODO: This is not fully accurate.
        return 
$this->pDereferenceLhs($node);
    }

    /**
     * @param Node[] 
$nodes
     * @return bool
     */
    protected function hasNodeWithComments(array 
$nodes) {
        foreach (
$nodes as $node) {
            if (
$node && $node->getComments()) {
                return true;
            }
        }
        return false;
    }

    protected function pMaybeMultiline(array 
$nodes, bool $trailingComma = false) {
        if (!
$this->hasNodeWithComments($nodes)) {
            return 
$this->pCommaSeparated($nodes);
        } else {
            return 
$this->pCommaSeparatedMultiline($nodes$trailingComma) . $this->nl;
        }
    }

    protected function pAttrGroups(array 
$nodes, bool $inline = false): string {
        
$result = '';
        
$sep = $inline ? ' ' : $this->nl;
        foreach (
$nodes as $node) {
            
$result .= $this->p($node) . $sep;
        }

        return 
$result;
    }
}
Онлайн: 0
Реклама