| 1: | <?php declare(strict_types=1); |
| 2: | |
| 3: | namespace PhpParser\PrettyPrinter; |
| 4: | |
| 5: | use PhpParser\Node; |
| 6: | use PhpParser\Node\Expr; |
| 7: | use PhpParser\Node\Expr\AssignOp; |
| 8: | use PhpParser\Node\Expr\BinaryOp; |
| 9: | use PhpParser\Node\Expr\Cast; |
| 10: | use PhpParser\Node\Name; |
| 11: | use PhpParser\Node\Scalar; |
| 12: | use PhpParser\Node\Scalar\MagicConst; |
| 13: | use PhpParser\Node\Stmt; |
| 14: | use PhpParser\PrettyPrinterAbstract; |
| 15: | |
| 16: | class Standard extends PrettyPrinterAbstract |
| 17: | { |
| 18: | |
| 19: | |
| 20: | protected function pParam(Node\Param $node) { |
| 21: | return $this->pAttrGroups($node->attrGroups, true) |
| 22: | . $this->pModifiers($node->flags) |
| 23: | . ($node->type ? $this->p($node->type) . ' ' : '') |
| 24: | . ($node->byRef ? '&' : '') |
| 25: | . ($node->variadic ? '...' : '') |
| 26: | . $this->p($node->var) |
| 27: | . ($node->default ? ' = ' . $this->p($node->default) : ''); |
| 28: | } |
| 29: | |
| 30: | protected function pArg(Node\Arg $node) { |
| 31: | return ($node->name ? $node->name->toString() . ': ' : '') |
| 32: | . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') |
| 33: | . $this->p($node->value); |
| 34: | } |
| 35: | |
| 36: | protected function pVariadicPlaceholder(Node\VariadicPlaceholder $node) { |
| 37: | return '...'; |
| 38: | } |
| 39: | |
| 40: | protected function pConst(Node\Const_ $node) { |
| 41: | return $node->name . ' = ' . $this->p($node->value); |
| 42: | } |
| 43: | |
| 44: | protected function pNullableType(Node\NullableType $node) { |
| 45: | return '?' . $this->p($node->type); |
| 46: | } |
| 47: | |
| 48: | protected function pUnionType(Node\UnionType $node) { |
| 49: | $types = []; |
| 50: | foreach ($node->types as $typeNode) { |
| 51: | if ($typeNode instanceof Node\IntersectionType) { |
| 52: | $types[] = '('. $this->p($typeNode) . ')'; |
| 53: | continue; |
| 54: | } |
| 55: | $types[] = $this->p($typeNode); |
| 56: | } |
| 57: | return implode('|', $types); |
| 58: | } |
| 59: | |
| 60: | protected function pIntersectionType(Node\IntersectionType $node) { |
| 61: | return $this->pImplode($node->types, '&'); |
| 62: | } |
| 63: | |
| 64: | protected function pIdentifier(Node\Identifier $node) { |
| 65: | return $node->name; |
| 66: | } |
| 67: | |
| 68: | protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node) { |
| 69: | return '$' . $node->name; |
| 70: | } |
| 71: | |
| 72: | protected function pAttribute(Node\Attribute $node) { |
| 73: | return $this->p($node->name) |
| 74: | . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : ''); |
| 75: | } |
| 76: | |
| 77: | protected function pAttributeGroup(Node\AttributeGroup $node) { |
| 78: | return '#[' . $this->pCommaSeparated($node->attrs) . ']'; |
| 79: | } |
| 80: | |
| 81: | |
| 82: | |
| 83: | protected function pName(Name $node) { |
| 84: | return implode('\\', $node->parts); |
| 85: | } |
| 86: | |
| 87: | protected function pName_FullyQualified(Name\FullyQualified $node) { |
| 88: | return '\\' . implode('\\', $node->parts); |
| 89: | } |
| 90: | |
| 91: | protected function pName_Relative(Name\Relative $node) { |
| 92: | return 'namespace\\' . implode('\\', $node->parts); |
| 93: | } |
| 94: | |
| 95: | |
| 96: | |
| 97: | protected function pScalar_MagicConst_Class(MagicConst\Class_ $node) { |
| 98: | return '__CLASS__'; |
| 99: | } |
| 100: | |
| 101: | protected function pScalar_MagicConst_Dir(MagicConst\Dir $node) { |
| 102: | return '__DIR__'; |
| 103: | } |
| 104: | |
| 105: | protected function pScalar_MagicConst_File(MagicConst\File $node) { |
| 106: | return '__FILE__'; |
| 107: | } |
| 108: | |
| 109: | protected function pScalar_MagicConst_Function(MagicConst\Function_ $node) { |
| 110: | return '__FUNCTION__'; |
| 111: | } |
| 112: | |
| 113: | protected function pScalar_MagicConst_Line(MagicConst\Line $node) { |
| 114: | return '__LINE__'; |
| 115: | } |
| 116: | |
| 117: | protected function pScalar_MagicConst_Method(MagicConst\Method $node) { |
| 118: | return '__METHOD__'; |
| 119: | } |
| 120: | |
| 121: | protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) { |
| 122: | return '__NAMESPACE__'; |
| 123: | } |
| 124: | |
| 125: | protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) { |
| 126: | return '__TRAIT__'; |
| 127: | } |
| 128: | |
| 129: | |
| 130: | |
| 131: | protected function pScalar_String(Scalar\String_ $node) { |
| 132: | $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED); |
| 133: | switch ($kind) { |
| 134: | case Scalar\String_::KIND_NOWDOC: |
| 135: | $label = $node->getAttribute('docLabel'); |
| 136: | if ($label && !$this->containsEndLabel($node->value, $label)) { |
| 137: | if ($node->value === '') { |
| 138: | return "<<<'$label'\n$label" . $this->docStringEndToken; |
| 139: | } |
| 140: | |
| 141: | return "<<<'$label'\n$node->value\n$label" |
| 142: | . $this->docStringEndToken; |
| 143: | } |
| 144: | |
| 145: | case Scalar\String_::KIND_SINGLE_QUOTED: |
| 146: | return $this->pSingleQuotedString($node->value); |
| 147: | case Scalar\String_::KIND_HEREDOC: |
| 148: | $label = $node->getAttribute('docLabel'); |
| 149: | if ($label && !$this->containsEndLabel($node->value, $label)) { |
| 150: | if ($node->value === '') { |
| 151: | return "<<<$label\n$label" . $this->docStringEndToken; |
| 152: | } |
| 153: | |
| 154: | $escaped = $this->escapeString($node->value, null); |
| 155: | return "<<<$label\n" . $escaped . "\n$label" |
| 156: | . $this->docStringEndToken; |
| 157: | } |
| 158: | |
| 159: | case Scalar\String_::KIND_DOUBLE_QUOTED: |
| 160: | return '"' . $this->escapeString($node->value, '"') . '"'; |
| 161: | } |
| 162: | throw new \Exception('Invalid string kind'); |
| 163: | } |
| 164: | |
| 165: | protected function pScalar_Encapsed(Scalar\Encapsed $node) { |
| 166: | if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) { |
| 167: | $label = $node->getAttribute('docLabel'); |
| 168: | if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) { |
| 169: | if (count($node->parts) === 1 |
| 170: | && $node->parts[0] instanceof Scalar\EncapsedStringPart |
| 171: | && $node->parts[0]->value === '' |
| 172: | ) { |
| 173: | return "<<<$label\n$label" . $this->docStringEndToken; |
| 174: | } |
| 175: | |
| 176: | return "<<<$label\n" . $this->pEncapsList($node->parts, null) . "\n$label" |
| 177: | . $this->docStringEndToken; |
| 178: | } |
| 179: | } |
| 180: | return '"' . $this->pEncapsList($node->parts, '"') . '"'; |
| 181: | } |
| 182: | |
| 183: | protected function pScalar_LNumber(Scalar\LNumber $node) { |
| 184: | if ($node->value === -\PHP_INT_MAX-1) { |
| 185: | |
| 186: | |
| 187: | return '(-' . \PHP_INT_MAX . '-1)'; |
| 188: | } |
| 189: | |
| 190: | $kind = $node->getAttribute('kind', Scalar\LNumber::KIND_DEC); |
| 191: | if (Scalar\LNumber::KIND_DEC === $kind) { |
| 192: | return (string) $node->value; |
| 193: | } |
| 194: | |
| 195: | if ($node->value < 0) { |
| 196: | $sign = '-'; |
| 197: | $str = (string) -$node->value; |
| 198: | } else { |
| 199: | $sign = ''; |
| 200: | $str = (string) $node->value; |
| 201: | } |
| 202: | switch ($kind) { |
| 203: | case Scalar\LNumber::KIND_BIN: |
| 204: | return $sign . '0b' . base_convert($str, 10, 2); |
| 205: | case Scalar\LNumber::KIND_OCT: |
| 206: | return $sign . '0' . base_convert($str, 10, 8); |
| 207: | case Scalar\LNumber::KIND_HEX: |
| 208: | return $sign . '0x' . base_convert($str, 10, 16); |
| 209: | } |
| 210: | throw new \Exception('Invalid number kind'); |
| 211: | } |
| 212: | |
| 213: | protected function pScalar_DNumber(Scalar\DNumber $node) { |
| 214: | if (!is_finite($node->value)) { |
| 215: | if ($node->value === \INF) { |
| 216: | return '\INF'; |
| 217: | } elseif ($node->value === -\INF) { |
| 218: | return '-\INF'; |
| 219: | } else { |
| 220: | return '\NAN'; |
| 221: | } |
| 222: | } |
| 223: | |
| 224: | |
| 225: | $stringValue = sprintf('%.16G', $node->value); |
| 226: | if ($node->value !== (double) $stringValue) { |
| 227: | $stringValue = sprintf('%.17G', $node->value); |
| 228: | } |
| 229: | |
| 230: | |
| 231: | |
| 232: | |
| 233: | $stringValue = str_replace(',', '.', $stringValue); |
| 234: | |
| 235: | |
| 236: | return preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue; |
| 237: | } |
| 238: | |
| 239: | protected function pScalar_EncapsedStringPart(Scalar\EncapsedStringPart $node) { |
| 240: | throw new \LogicException('Cannot directly print EncapsedStringPart'); |
| 241: | } |
| 242: | |
| 243: | |
| 244: | |
| 245: | protected function pExpr_Assign(Expr\Assign $node) { |
| 246: | return $this->pInfixOp(Expr\Assign::class, $node->var, ' = ', $node->expr); |
| 247: | } |
| 248: | |
| 249: | protected function pExpr_AssignRef(Expr\AssignRef $node) { |
| 250: | return $this->pInfixOp(Expr\AssignRef::class, $node->var, ' =& ', $node->expr); |
| 251: | } |
| 252: | |
| 253: | protected function pExpr_AssignOp_Plus(AssignOp\Plus $node) { |
| 254: | return $this->pInfixOp(AssignOp\Plus::class, $node->var, ' += ', $node->expr); |
| 255: | } |
| 256: | |
| 257: | protected function pExpr_AssignOp_Minus(AssignOp\Minus $node) { |
| 258: | return $this->pInfixOp(AssignOp\Minus::class, $node->var, ' -= ', $node->expr); |
| 259: | } |
| 260: | |
| 261: | protected function pExpr_AssignOp_Mul(AssignOp\Mul $node) { |
| 262: | return $this->pInfixOp(AssignOp\Mul::class, $node->var, ' *= ', $node->expr); |
| 263: | } |
| 264: | |
| 265: | protected function pExpr_AssignOp_Div(AssignOp\Div $node) { |
| 266: | return $this->pInfixOp(AssignOp\Div::class, $node->var, ' /= ', $node->expr); |
| 267: | } |
| 268: | |
| 269: | protected function pExpr_AssignOp_Concat(AssignOp\Concat $node) { |
| 270: | return $this->pInfixOp(AssignOp\Concat::class, $node->var, ' .= ', $node->expr); |
| 271: | } |
| 272: | |
| 273: | protected function pExpr_AssignOp_Mod(AssignOp\Mod $node) { |
| 274: | return $this->pInfixOp(AssignOp\Mod::class, $node->var, ' %= ', $node->expr); |
| 275: | } |
| 276: | |
| 277: | protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) { |
| 278: | return $this->pInfixOp(AssignOp\BitwiseAnd::class, $node->var, ' &= ', $node->expr); |
| 279: | } |
| 280: | |
| 281: | protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) { |
| 282: | return $this->pInfixOp(AssignOp\BitwiseOr::class, $node->var, ' |= ', $node->expr); |
| 283: | } |
| 284: | |
| 285: | protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) { |
| 286: | return $this->pInfixOp(AssignOp\BitwiseXor::class, $node->var, ' ^= ', $node->expr); |
| 287: | } |
| 288: | |
| 289: | protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) { |
| 290: | return $this->pInfixOp(AssignOp\ShiftLeft::class, $node->var, ' <<= ', $node->expr); |
| 291: | } |
| 292: | |
| 293: | protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) { |
| 294: | return $this->pInfixOp(AssignOp\ShiftRight::class, $node->var, ' >>= ', $node->expr); |
| 295: | } |
| 296: | |
| 297: | protected function pExpr_AssignOp_Pow(AssignOp\Pow $node) { |
| 298: | return $this->pInfixOp(AssignOp\Pow::class, $node->var, ' **= ', $node->expr); |
| 299: | } |
| 300: | |
| 301: | protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node) { |
| 302: | return $this->pInfixOp(AssignOp\Coalesce::class, $node->var, ' ??= ', $node->expr); |
| 303: | } |
| 304: | |
| 305: | |
| 306: | |
| 307: | protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) { |
| 308: | return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right); |
| 309: | } |
| 310: | |
| 311: | protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) { |
| 312: | return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right); |
| 313: | } |
| 314: | |
| 315: | protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) { |
| 316: | return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right); |
| 317: | } |
| 318: | |
| 319: | protected function pExpr_BinaryOp_Div(BinaryOp\Div $node) { |
| 320: | return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right); |
| 321: | } |
| 322: | |
| 323: | protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) { |
| 324: | return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right); |
| 325: | } |
| 326: | |
| 327: | protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) { |
| 328: | return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right); |
| 329: | } |
| 330: | |
| 331: | protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) { |
| 332: | return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right); |
| 333: | } |
| 334: | |
| 335: | protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) { |
| 336: | return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right); |
| 337: | } |
| 338: | |
| 339: | protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) { |
| 340: | return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right); |
| 341: | } |
| 342: | |
| 343: | protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) { |
| 344: | return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right); |
| 345: | } |
| 346: | |
| 347: | protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) { |
| 348: | return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right); |
| 349: | } |
| 350: | |
| 351: | protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) { |
| 352: | return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right); |
| 353: | } |
| 354: | |
| 355: | protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) { |
| 356: | return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right); |
| 357: | } |
| 358: | |
| 359: | protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) { |
| 360: | return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right); |
| 361: | } |
| 362: | |
| 363: | protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) { |
| 364: | return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right); |
| 365: | } |
| 366: | |
| 367: | protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) { |
| 368: | return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right); |
| 369: | } |
| 370: | |
| 371: | protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) { |
| 372: | return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right); |
| 373: | } |
| 374: | |
| 375: | protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) { |
| 376: | return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right); |
| 377: | } |
| 378: | |
| 379: | protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) { |
| 380: | return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right); |
| 381: | } |
| 382: | |
| 383: | protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) { |
| 384: | return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right); |
| 385: | } |
| 386: | |
| 387: | protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) { |
| 388: | return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right); |
| 389: | } |
| 390: | |
| 391: | protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) { |
| 392: | return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right); |
| 393: | } |
| 394: | |
| 395: | protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) { |
| 396: | return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right); |
| 397: | } |
| 398: | |
| 399: | protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) { |
| 400: | return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right); |
| 401: | } |
| 402: | |
| 403: | protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) { |
| 404: | return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right); |
| 405: | } |
| 406: | |
| 407: | protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) { |
| 408: | return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right); |
| 409: | } |
| 410: | |
| 411: | protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) { |
| 412: | return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right); |
| 413: | } |
| 414: | |
| 415: | protected function pExpr_Instanceof(Expr\Instanceof_ $node) { |
| 416: | list($precedence, $associativity) = $this->precedenceMap[Expr\Instanceof_::class]; |
| 417: | return $this->pPrec($node->expr, $precedence, $associativity, -1) |
| 418: | . ' instanceof ' |
| 419: | . $this->pNewVariable($node->class); |
| 420: | } |
| 421: | |
| 422: | |
| 423: | |
| 424: | protected function pExpr_BooleanNot(Expr\BooleanNot $node) { |
| 425: | return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr); |
| 426: | } |
| 427: | |
| 428: | protected function pExpr_BitwiseNot(Expr\BitwiseNot $node) { |
| 429: | return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr); |
| 430: | } |
| 431: | |
| 432: | protected function pExpr_UnaryMinus(Expr\UnaryMinus $node) { |
| 433: | if ($node->expr instanceof Expr\UnaryMinus || $node->expr instanceof Expr\PreDec) { |
| 434: | |
| 435: | return '-(' . $this->p($node->expr) . ')'; |
| 436: | } |
| 437: | return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr); |
| 438: | } |
| 439: | |
| 440: | protected function pExpr_UnaryPlus(Expr\UnaryPlus $node) { |
| 441: | if ($node->expr instanceof Expr\UnaryPlus || $node->expr instanceof Expr\PreInc) { |
| 442: | |
| 443: | return '+(' . $this->p($node->expr) . ')'; |
| 444: | } |
| 445: | return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr); |
| 446: | } |
| 447: | |
| 448: | protected function pExpr_PreInc(Expr\PreInc $node) { |
| 449: | return $this->pPrefixOp(Expr\PreInc::class, '++', $node->var); |
| 450: | } |
| 451: | |
| 452: | protected function pExpr_PreDec(Expr\PreDec $node) { |
| 453: | return $this->pPrefixOp(Expr\PreDec::class, '--', $node->var); |
| 454: | } |
| 455: | |
| 456: | protected function pExpr_PostInc(Expr\PostInc $node) { |
| 457: | return $this->pPostfixOp(Expr\PostInc::class, $node->var, '++'); |
| 458: | } |
| 459: | |
| 460: | protected function pExpr_PostDec(Expr\PostDec $node) { |
| 461: | return $this->pPostfixOp(Expr\PostDec::class, $node->var, '--'); |
| 462: | } |
| 463: | |
| 464: | protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) { |
| 465: | return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr); |
| 466: | } |
| 467: | |
| 468: | protected function pExpr_YieldFrom(Expr\YieldFrom $node) { |
| 469: | return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr); |
| 470: | } |
| 471: | |
| 472: | protected function pExpr_Print(Expr\Print_ $node) { |
| 473: | return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr); |
| 474: | } |
| 475: | |
| 476: | |
| 477: | |
| 478: | protected function pExpr_Cast_Int(Cast\Int_ $node) { |
| 479: | return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr); |
| 480: | } |
| 481: | |
| 482: | protected function pExpr_Cast_Double(Cast\Double $node) { |
| 483: | $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE); |
| 484: | if ($kind === Cast\Double::KIND_DOUBLE) { |
| 485: | $cast = '(double)'; |
| 486: | } elseif ($kind === Cast\Double::KIND_FLOAT) { |
| 487: | $cast = '(float)'; |
| 488: | } elseif ($kind === Cast\Double::KIND_REAL) { |
| 489: | $cast = '(real)'; |
| 490: | } |
| 491: | return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr); |
| 492: | } |
| 493: | |
| 494: | protected function pExpr_Cast_String(Cast\String_ $node) { |
| 495: | return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr); |
| 496: | } |
| 497: | |
| 498: | protected function pExpr_Cast_Array(Cast\Array_ $node) { |
| 499: | return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr); |
| 500: | } |
| 501: | |
| 502: | protected function pExpr_Cast_Object(Cast\Object_ $node) { |
| 503: | return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr); |
| 504: | } |
| 505: | |
| 506: | protected function pExpr_Cast_Bool(Cast\Bool_ $node) { |
| 507: | return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr); |
| 508: | } |
| 509: | |
| 510: | protected function pExpr_Cast_Unset(Cast\Unset_ $node) { |
| 511: | return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr); |
| 512: | } |
| 513: | |
| 514: | |
| 515: | |
| 516: | protected function pExpr_FuncCall(Expr\FuncCall $node) { |
| 517: | return $this->pCallLhs($node->name) |
| 518: | . '(' . $this->pMaybeMultiline($node->args) . ')'; |
| 519: | } |
| 520: | |
| 521: | protected function pExpr_MethodCall(Expr\MethodCall $node) { |
| 522: | return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name) |
| 523: | . '(' . $this->pMaybeMultiline($node->args) . ')'; |
| 524: | } |
| 525: | |
| 526: | protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node) { |
| 527: | return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name) |
| 528: | . '(' . $this->pMaybeMultiline($node->args) . ')'; |
| 529: | } |
| 530: | |
| 531: | protected function pExpr_StaticCall(Expr\StaticCall $node) { |
| 532: | return $this->pDereferenceLhs($node->class) . '::' |
| 533: | . ($node->name instanceof Expr |
| 534: | ? ($node->name instanceof Expr\Variable |
| 535: | ? $this->p($node->name) |
| 536: | : '{' . $this->p($node->name) . '}') |
| 537: | : $node->name) |
| 538: | . '(' . $this->pMaybeMultiline($node->args) . ')'; |
| 539: | } |
| 540: | |
| 541: | protected function pExpr_Empty(Expr\Empty_ $node) { |
| 542: | return 'empty(' . $this->p($node->expr) . ')'; |
| 543: | } |
| 544: | |
| 545: | protected function pExpr_Isset(Expr\Isset_ $node) { |
| 546: | return 'isset(' . $this->pCommaSeparated($node->vars) . ')'; |
| 547: | } |
| 548: | |
| 549: | protected function pExpr_Eval(Expr\Eval_ $node) { |
| 550: | return 'eval(' . $this->p($node->expr) . ')'; |
| 551: | } |
| 552: | |
| 553: | protected function pExpr_Include(Expr\Include_ $node) { |
| 554: | static $map = [ |
| 555: | Expr\Include_::TYPE_INCLUDE => 'include', |
| 556: | Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once', |
| 557: | Expr\Include_::TYPE_REQUIRE => 'require', |
| 558: | Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once', |
| 559: | ]; |
| 560: | |
| 561: | return $map[$node->type] . ' ' . $this->p($node->expr); |
| 562: | } |
| 563: | |
| 564: | protected function pExpr_List(Expr\List_ $node) { |
| 565: | return 'list(' . $this->pCommaSeparated($node->items) . ')'; |
| 566: | } |
| 567: | |
| 568: | |
| 569: | |
| 570: | protected function pExpr_Error(Expr\Error $node) { |
| 571: | throw new \LogicException('Cannot pretty-print AST with Error nodes'); |
| 572: | } |
| 573: | |
| 574: | protected function pExpr_Variable(Expr\Variable $node) { |
| 575: | if ($node->name instanceof Expr) { |
| 576: | return '${' . $this->p($node->name) . '}'; |
| 577: | } else { |
| 578: | return '$' . $node->name; |
| 579: | } |
| 580: | } |
| 581: | |
| 582: | protected function pExpr_Array(Expr\Array_ $node) { |
| 583: | $syntax = $node->getAttribute('kind', |
| 584: | $this->options['shortArraySyntax'] ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); |
| 585: | if ($syntax === Expr\Array_::KIND_SHORT) { |
| 586: | return '[' . $this->pMaybeMultiline($node->items, true) . ']'; |
| 587: | } else { |
| 588: | return 'array(' . $this->pMaybeMultiline($node->items, true) . ')'; |
| 589: | } |
| 590: | } |
| 591: | |
| 592: | protected function pExpr_ArrayItem(Expr\ArrayItem $node) { |
| 593: | return (null !== $node->key ? $this->p($node->key) . ' => ' : '') |
| 594: | . ($node->byRef ? '&' : '') |
| 595: | . ($node->unpack ? '...' : '') |
| 596: | . $this->p($node->value); |
| 597: | } |
| 598: | |
| 599: | protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) { |
| 600: | return $this->pDereferenceLhs($node->var) |
| 601: | . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']'; |
| 602: | } |
| 603: | |
| 604: | protected function pExpr_ConstFetch(Expr\ConstFetch $node) { |
| 605: | return $this->p($node->name); |
| 606: | } |
| 607: | |
| 608: | protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) { |
| 609: | return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name); |
| 610: | } |
| 611: | |
| 612: | protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) { |
| 613: | return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name); |
| 614: | } |
| 615: | |
| 616: | protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node) { |
| 617: | return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name); |
| 618: | } |
| 619: | |
| 620: | protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) { |
| 621: | return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); |
| 622: | } |
| 623: | |
| 624: | protected function pExpr_ShellExec(Expr\ShellExec $node) { |
| 625: | return '`' . $this->pEncapsList($node->parts, '`') . '`'; |
| 626: | } |
| 627: | |
| 628: | protected function pExpr_Closure(Expr\Closure $node) { |
| 629: | return $this->pAttrGroups($node->attrGroups, true) |
| 630: | . ($node->static ? 'static ' : '') |
| 631: | . 'function ' . ($node->byRef ? '&' : '') |
| 632: | . '(' . $this->pCommaSeparated($node->params) . ')' |
| 633: | . (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')' : '') |
| 634: | . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') |
| 635: | . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 636: | } |
| 637: | |
| 638: | protected function pExpr_Match(Expr\Match_ $node) { |
| 639: | return 'match (' . $this->p($node->cond) . ') {' |
| 640: | . $this->pCommaSeparatedMultiline($node->arms, true) |
| 641: | . $this->nl |
| 642: | . '}'; |
| 643: | } |
| 644: | |
| 645: | protected function pMatchArm(Node\MatchArm $node) { |
| 646: | return ($node->conds ? $this->pCommaSeparated($node->conds) : 'default') |
| 647: | . ' => ' . $this->p($node->body); |
| 648: | } |
| 649: | |
| 650: | protected function pExpr_ArrowFunction(Expr\ArrowFunction $node) { |
| 651: | return $this->pAttrGroups($node->attrGroups, true) |
| 652: | . ($node->static ? 'static ' : '') |
| 653: | . 'fn' . ($node->byRef ? '&' : '') |
| 654: | . '(' . $this->pCommaSeparated($node->params) . ')' |
| 655: | . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') |
| 656: | . ' => ' |
| 657: | . $this->p($node->expr); |
| 658: | } |
| 659: | |
| 660: | protected function pExpr_ClosureUse(Expr\ClosureUse $node) { |
| 661: | return ($node->byRef ? '&' : '') . $this->p($node->var); |
| 662: | } |
| 663: | |
| 664: | protected function pExpr_New(Expr\New_ $node) { |
| 665: | if ($node->class instanceof Stmt\Class_) { |
| 666: | $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : ''; |
| 667: | return 'new ' . $this->pClassCommon($node->class, $args); |
| 668: | } |
| 669: | return 'new ' . $this->pNewVariable($node->class) |
| 670: | . '(' . $this->pMaybeMultiline($node->args) . ')'; |
| 671: | } |
| 672: | |
| 673: | protected function pExpr_Clone(Expr\Clone_ $node) { |
| 674: | return 'clone ' . $this->p($node->expr); |
| 675: | } |
| 676: | |
| 677: | protected function pExpr_Ternary(Expr\Ternary $node) { |
| 678: | |
| 679: | |
| 680: | return $this->pInfixOp(Expr\Ternary::class, |
| 681: | $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else |
| 682: | ); |
| 683: | } |
| 684: | |
| 685: | protected function pExpr_Exit(Expr\Exit_ $node) { |
| 686: | $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE); |
| 687: | return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die') |
| 688: | . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : ''); |
| 689: | } |
| 690: | |
| 691: | protected function pExpr_Throw(Expr\Throw_ $node) { |
| 692: | return 'throw ' . $this->p($node->expr); |
| 693: | } |
| 694: | |
| 695: | protected function pExpr_Yield(Expr\Yield_ $node) { |
| 696: | if ($node->value === null) { |
| 697: | return 'yield'; |
| 698: | } else { |
| 699: | |
| 700: | return '(yield ' |
| 701: | . ($node->key !== null ? $this->p($node->key) . ' => ' : '') |
| 702: | . $this->p($node->value) |
| 703: | . ')'; |
| 704: | } |
| 705: | } |
| 706: | |
| 707: | |
| 708: | |
| 709: | protected function pStmt_Namespace(Stmt\Namespace_ $node) { |
| 710: | if ($this->canUseSemicolonNamespaces) { |
| 711: | return 'namespace ' . $this->p($node->name) . ';' |
| 712: | . $this->nl . $this->pStmts($node->stmts, false); |
| 713: | } else { |
| 714: | return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '') |
| 715: | . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 716: | } |
| 717: | } |
| 718: | |
| 719: | protected function pStmt_Use(Stmt\Use_ $node) { |
| 720: | return 'use ' . $this->pUseType($node->type) |
| 721: | . $this->pCommaSeparated($node->uses) . ';'; |
| 722: | } |
| 723: | |
| 724: | protected function pStmt_GroupUse(Stmt\GroupUse $node) { |
| 725: | return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix) |
| 726: | . '\{' . $this->pCommaSeparated($node->uses) . '};'; |
| 727: | } |
| 728: | |
| 729: | protected function pStmt_UseUse(Stmt\UseUse $node) { |
| 730: | return $this->pUseType($node->type) . $this->p($node->name) |
| 731: | . (null !== $node->alias ? ' as ' . $node->alias : ''); |
| 732: | } |
| 733: | |
| 734: | protected function pUseType($type) { |
| 735: | return $type === Stmt\Use_::TYPE_FUNCTION ? 'function ' |
| 736: | : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : ''); |
| 737: | } |
| 738: | |
| 739: | protected function pStmt_Interface(Stmt\Interface_ $node) { |
| 740: | return $this->pAttrGroups($node->attrGroups) |
| 741: | . 'interface ' . $node->name |
| 742: | . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '') |
| 743: | . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 744: | } |
| 745: | |
| 746: | protected function pStmt_Enum(Stmt\Enum_ $node) { |
| 747: | return $this->pAttrGroups($node->attrGroups) |
| 748: | . 'enum ' . $node->name |
| 749: | . ($node->scalarType ? " : $node->scalarType" : '') |
| 750: | . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') |
| 751: | . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 752: | } |
| 753: | |
| 754: | protected function pStmt_Class(Stmt\Class_ $node) { |
| 755: | return $this->pClassCommon($node, ' ' . $node->name); |
| 756: | } |
| 757: | |
| 758: | protected function pStmt_Trait(Stmt\Trait_ $node) { |
| 759: | return $this->pAttrGroups($node->attrGroups) |
| 760: | . 'trait ' . $node->name |
| 761: | . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 762: | } |
| 763: | |
| 764: | protected function pStmt_EnumCase(Stmt\EnumCase $node) { |
| 765: | return $this->pAttrGroups($node->attrGroups) |
| 766: | . 'case ' . $node->name |
| 767: | . ($node->expr ? ' = ' . $this->p($node->expr) : '') |
| 768: | . ';'; |
| 769: | } |
| 770: | |
| 771: | protected function pStmt_TraitUse(Stmt\TraitUse $node) { |
| 772: | return 'use ' . $this->pCommaSeparated($node->traits) |
| 773: | . (empty($node->adaptations) |
| 774: | ? ';' |
| 775: | : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}'); |
| 776: | } |
| 777: | |
| 778: | protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) { |
| 779: | return $this->p($node->trait) . '::' . $node->method |
| 780: | . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';'; |
| 781: | } |
| 782: | |
| 783: | protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) { |
| 784: | return (null !== $node->trait ? $this->p($node->trait) . '::' : '') |
| 785: | . $node->method . ' as' |
| 786: | . (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '') |
| 787: | . (null !== $node->newName ? ' ' . $node->newName : '') |
| 788: | . ';'; |
| 789: | } |
| 790: | |
| 791: | protected function pStmt_Property(Stmt\Property $node) { |
| 792: | return $this->pAttrGroups($node->attrGroups) |
| 793: | . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) |
| 794: | . ($node->type ? $this->p($node->type) . ' ' : '') |
| 795: | . $this->pCommaSeparated($node->props) . ';'; |
| 796: | } |
| 797: | |
| 798: | protected function pStmt_PropertyProperty(Stmt\PropertyProperty $node) { |
| 799: | return '$' . $node->name |
| 800: | . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); |
| 801: | } |
| 802: | |
| 803: | protected function pStmt_ClassMethod(Stmt\ClassMethod $node) { |
| 804: | return $this->pAttrGroups($node->attrGroups) |
| 805: | . $this->pModifiers($node->flags) |
| 806: | . 'function ' . ($node->byRef ? '&' : '') . $node->name |
| 807: | . '(' . $this->pMaybeMultiline($node->params) . ')' |
| 808: | . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') |
| 809: | . (null !== $node->stmts |
| 810: | ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}' |
| 811: | : ';'); |
| 812: | } |
| 813: | |
| 814: | protected function pStmt_ClassConst(Stmt\ClassConst $node) { |
| 815: | return $this->pAttrGroups($node->attrGroups) |
| 816: | . $this->pModifiers($node->flags) |
| 817: | . 'const ' . $this->pCommaSeparated($node->consts) . ';'; |
| 818: | } |
| 819: | |
| 820: | protected function pStmt_Function(Stmt\Function_ $node) { |
| 821: | return $this->pAttrGroups($node->attrGroups) |
| 822: | . 'function ' . ($node->byRef ? '&' : '') . $node->name |
| 823: | . '(' . $this->pCommaSeparated($node->params) . ')' |
| 824: | . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') |
| 825: | . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 826: | } |
| 827: | |
| 828: | protected function pStmt_Const(Stmt\Const_ $node) { |
| 829: | return 'const ' . $this->pCommaSeparated($node->consts) . ';'; |
| 830: | } |
| 831: | |
| 832: | protected function pStmt_Declare(Stmt\Declare_ $node) { |
| 833: | return 'declare (' . $this->pCommaSeparated($node->declares) . ')' |
| 834: | . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); |
| 835: | } |
| 836: | |
| 837: | protected function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) { |
| 838: | return $node->key . '=' . $this->p($node->value); |
| 839: | } |
| 840: | |
| 841: | |
| 842: | |
| 843: | protected function pStmt_If(Stmt\If_ $node) { |
| 844: | return 'if (' . $this->p($node->cond) . ') {' |
| 845: | . $this->pStmts($node->stmts) . $this->nl . '}' |
| 846: | . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '') |
| 847: | . (null !== $node->else ? ' ' . $this->p($node->else) : ''); |
| 848: | } |
| 849: | |
| 850: | protected function pStmt_ElseIf(Stmt\ElseIf_ $node) { |
| 851: | return 'elseif (' . $this->p($node->cond) . ') {' |
| 852: | . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 853: | } |
| 854: | |
| 855: | protected function pStmt_Else(Stmt\Else_ $node) { |
| 856: | return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 857: | } |
| 858: | |
| 859: | protected function pStmt_For(Stmt\For_ $node) { |
| 860: | return 'for (' |
| 861: | . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '') |
| 862: | . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '') |
| 863: | . $this->pCommaSeparated($node->loop) |
| 864: | . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 865: | } |
| 866: | |
| 867: | protected function pStmt_Foreach(Stmt\Foreach_ $node) { |
| 868: | return 'foreach (' . $this->p($node->expr) . ' as ' |
| 869: | . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '') |
| 870: | . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' |
| 871: | . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 872: | } |
| 873: | |
| 874: | protected function pStmt_While(Stmt\While_ $node) { |
| 875: | return 'while (' . $this->p($node->cond) . ') {' |
| 876: | . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 877: | } |
| 878: | |
| 879: | protected function pStmt_Do(Stmt\Do_ $node) { |
| 880: | return 'do {' . $this->pStmts($node->stmts) . $this->nl |
| 881: | . '} while (' . $this->p($node->cond) . ');'; |
| 882: | } |
| 883: | |
| 884: | protected function pStmt_Switch(Stmt\Switch_ $node) { |
| 885: | return 'switch (' . $this->p($node->cond) . ') {' |
| 886: | . $this->pStmts($node->cases) . $this->nl . '}'; |
| 887: | } |
| 888: | |
| 889: | protected function pStmt_Case(Stmt\Case_ $node) { |
| 890: | return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':' |
| 891: | . $this->pStmts($node->stmts); |
| 892: | } |
| 893: | |
| 894: | protected function pStmt_TryCatch(Stmt\TryCatch $node) { |
| 895: | return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}' |
| 896: | . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '') |
| 897: | . ($node->finally !== null ? ' ' . $this->p($node->finally) : ''); |
| 898: | } |
| 899: | |
| 900: | protected function pStmt_Catch(Stmt\Catch_ $node) { |
| 901: | return 'catch (' . $this->pImplode($node->types, '|') |
| 902: | . ($node->var !== null ? ' ' . $this->p($node->var) : '') |
| 903: | . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 904: | } |
| 905: | |
| 906: | protected function pStmt_Finally(Stmt\Finally_ $node) { |
| 907: | return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 908: | } |
| 909: | |
| 910: | protected function pStmt_Break(Stmt\Break_ $node) { |
| 911: | return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; |
| 912: | } |
| 913: | |
| 914: | protected function pStmt_Continue(Stmt\Continue_ $node) { |
| 915: | return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; |
| 916: | } |
| 917: | |
| 918: | protected function pStmt_Return(Stmt\Return_ $node) { |
| 919: | return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';'; |
| 920: | } |
| 921: | |
| 922: | protected function pStmt_Throw(Stmt\Throw_ $node) { |
| 923: | return 'throw ' . $this->p($node->expr) . ';'; |
| 924: | } |
| 925: | |
| 926: | protected function pStmt_Label(Stmt\Label $node) { |
| 927: | return $node->name . ':'; |
| 928: | } |
| 929: | |
| 930: | protected function pStmt_Goto(Stmt\Goto_ $node) { |
| 931: | return 'goto ' . $node->name . ';'; |
| 932: | } |
| 933: | |
| 934: | |
| 935: | |
| 936: | protected function pStmt_Expression(Stmt\Expression $node) { |
| 937: | return $this->p($node->expr) . ';'; |
| 938: | } |
| 939: | |
| 940: | protected function pStmt_Echo(Stmt\Echo_ $node) { |
| 941: | return 'echo ' . $this->pCommaSeparated($node->exprs) . ';'; |
| 942: | } |
| 943: | |
| 944: | protected function pStmt_Static(Stmt\Static_ $node) { |
| 945: | return 'static ' . $this->pCommaSeparated($node->vars) . ';'; |
| 946: | } |
| 947: | |
| 948: | protected function pStmt_Global(Stmt\Global_ $node) { |
| 949: | return 'global ' . $this->pCommaSeparated($node->vars) . ';'; |
| 950: | } |
| 951: | |
| 952: | protected function pStmt_StaticVar(Stmt\StaticVar $node) { |
| 953: | return $this->p($node->var) |
| 954: | . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); |
| 955: | } |
| 956: | |
| 957: | protected function pStmt_Unset(Stmt\Unset_ $node) { |
| 958: | return 'unset(' . $this->pCommaSeparated($node->vars) . ');'; |
| 959: | } |
| 960: | |
| 961: | protected function pStmt_InlineHTML(Stmt\InlineHTML $node) { |
| 962: | $newline = $node->getAttribute('hasLeadingNewline', true) ? "\n" : ''; |
| 963: | return '?>' . $newline . $node->value . '<?php '; |
| 964: | } |
| 965: | |
| 966: | protected function pStmt_HaltCompiler(Stmt\HaltCompiler $node) { |
| 967: | return '__halt_compiler();' . $node->remaining; |
| 968: | } |
| 969: | |
| 970: | protected function pStmt_Nop(Stmt\Nop $node) { |
| 971: | return ''; |
| 972: | } |
| 973: | |
| 974: | |
| 975: | |
| 976: | protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) { |
| 977: | return $this->pAttrGroups($node->attrGroups, $node->name === null) |
| 978: | . $this->pModifiers($node->flags) |
| 979: | . 'class' . $afterClassToken |
| 980: | . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '') |
| 981: | . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') |
| 982: | . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; |
| 983: | } |
| 984: | |
| 985: | protected function pObjectProperty($node) { |
| 986: | if ($node instanceof Expr) { |
| 987: | return '{' . $this->p($node) . '}'; |
| 988: | } else { |
| 989: | return $node; |
| 990: | } |
| 991: | } |
| 992: | |
| 993: | protected function pEncapsList(array $encapsList, $quote) { |
| 994: | $return = ''; |
| 995: | foreach ($encapsList as $element) { |
| 996: | if ($element instanceof Scalar\EncapsedStringPart) { |
| 997: | $return .= $this->escapeString($element->value, $quote); |
| 998: | } else { |
| 999: | $return .= '{' . $this->p($element) . '}'; |
| 1000: | } |
| 1001: | } |
| 1002: | |
| 1003: | return $return; |
| 1004: | } |
| 1005: | |
| 1006: | protected function pSingleQuotedString(string $string) { |
| 1007: | return '\'' . addcslashes($string, '\'\\') . '\''; |
| 1008: | } |
| 1009: | |
| 1010: | protected function escapeString($string, $quote) { |
| 1011: | if (null === $quote) { |
| 1012: | |
| 1013: | $escaped = addcslashes($string, "\t\f\v$\\"); |
| 1014: | } else { |
| 1015: | $escaped = addcslashes($string, "\n\r\t\f\v$" . $quote . "\\"); |
| 1016: | } |
| 1017: | |
| 1018: | |
| 1019: | |
| 1020: | $regex = '/( |
| 1021: | [\x00-\x08\x0E-\x1F] # Control characters |
| 1022: | | [\xC0-\xC1] # Invalid UTF-8 Bytes |
| 1023: | | [\xF5-\xFF] # Invalid UTF-8 Bytes |
| 1024: | | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point |
| 1025: | | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point |
| 1026: | | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start |
| 1027: | | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start |
| 1028: | | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start |
| 1029: | | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle |
| 1030: | | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence |
| 1031: | | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence |
| 1032: | | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence |
| 1033: | | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2) |
| 1034: | )/x'; |
| 1035: | return preg_replace_callback($regex, function ($matches) { |
| 1036: | assert(strlen($matches[0]) === 1); |
| 1037: | $hex = dechex(ord($matches[0]));; |
| 1038: | return '\\x' . str_pad($hex, 2, '0', \STR_PAD_LEFT); |
| 1039: | }, $escaped); |
| 1040: | } |
| 1041: | |
| 1042: | protected function containsEndLabel($string, $label, $atStart = true, $atEnd = true) { |
| 1043: | $start = $atStart ? '(?:^|[\r\n])' : '[\r\n]'; |
| 1044: | $end = $atEnd ? '(?:$|[;\r\n])' : '[;\r\n]'; |
| 1045: | return false !== strpos($string, $label) |
| 1046: | && preg_match('/' . $start . $label . $end . '/', $string); |
| 1047: | } |
| 1048: | |
| 1049: | protected function encapsedContainsEndLabel(array $parts, $label) { |
| 1050: | foreach ($parts as $i => $part) { |
| 1051: | $atStart = $i === 0; |
| 1052: | $atEnd = $i === count($parts) - 1; |
| 1053: | if ($part instanceof Scalar\EncapsedStringPart |
| 1054: | && $this->containsEndLabel($part->value, $label, $atStart, $atEnd) |
| 1055: | ) { |
| 1056: | return true; |
| 1057: | } |
| 1058: | } |
| 1059: | return false; |
| 1060: | } |
| 1061: | |
| 1062: | protected function pDereferenceLhs(Node $node) { |
| 1063: | if (!$this->dereferenceLhsRequiresParens($node)) { |
| 1064: | return $this->p($node); |
| 1065: | } else { |
| 1066: | return '(' . $this->p($node) . ')'; |
| 1067: | } |
| 1068: | } |
| 1069: | |
| 1070: | protected function pCallLhs(Node $node) { |
| 1071: | if (!$this->callLhsRequiresParens($node)) { |
| 1072: | return $this->p($node); |
| 1073: | } else { |
| 1074: | return '(' . $this->p($node) . ')'; |
| 1075: | } |
| 1076: | } |
| 1077: | |
| 1078: | protected function pNewVariable(Node $node) { |
| 1079: | |
| 1080: | return $this->pDereferenceLhs($node); |
| 1081: | } |
| 1082: | |
| 1083: | |
| 1084: | |
| 1085: | |
| 1086: | |
| 1087: | protected function hasNodeWithComments(array $nodes) { |
| 1088: | foreach ($nodes as $node) { |
| 1089: | if ($node && $node->getComments()) { |
| 1090: | return true; |
| 1091: | } |
| 1092: | } |
| 1093: | return false; |
| 1094: | } |
| 1095: | |
| 1096: | protected function pMaybeMultiline(array $nodes, bool $trailingComma = false) { |
| 1097: | if (!$this->hasNodeWithComments($nodes)) { |
| 1098: | return $this->pCommaSeparated($nodes); |
| 1099: | } else { |
| 1100: | return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; |
| 1101: | } |
| 1102: | } |
| 1103: | |
| 1104: | protected function pAttrGroups(array $nodes, bool $inline = false): string { |
| 1105: | $result = ''; |
| 1106: | $sep = $inline ? ' ' : $this->nl; |
| 1107: | foreach ($nodes as $node) { |
| 1108: | $result .= $this->p($node) . $sep; |
| 1109: | } |
| 1110: | |
| 1111: | return $result; |
| 1112: | } |
| 1113: | } |
| 1114: | |