Mercurial > hg > isophonics-drupal-site
comparison vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | c2387f117808 |
children |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
5 /* | 5 /* |
6 * This parser is based on a skeleton written by Moriyoshi Koizumi, which in | 6 * This parser is based on a skeleton written by Moriyoshi Koizumi, which in |
7 * turn is based on work by Masato Bito. | 7 * turn is based on work by Masato Bito. |
8 */ | 8 */ |
9 use PhpParser\Node\Expr; | 9 use PhpParser\Node\Expr; |
10 use PhpParser\Node\Expr\Cast\Double; | |
10 use PhpParser\Node\Name; | 11 use PhpParser\Node\Name; |
11 use PhpParser\Node\Param; | 12 use PhpParser\Node\Param; |
13 use PhpParser\Node\Scalar\Encapsed; | |
12 use PhpParser\Node\Scalar\LNumber; | 14 use PhpParser\Node\Scalar\LNumber; |
13 use PhpParser\Node\Scalar\String_; | 15 use PhpParser\Node\Scalar\String_; |
14 use PhpParser\Node\Stmt\Class_; | 16 use PhpParser\Node\Stmt\Class_; |
15 use PhpParser\Node\Stmt\ClassConst; | 17 use PhpParser\Node\Stmt\ClassConst; |
16 use PhpParser\Node\Stmt\ClassMethod; | 18 use PhpParser\Node\Stmt\ClassMethod; |
677 */ | 679 */ |
678 protected function getAttributesAt(int $pos) : array { | 680 protected function getAttributesAt(int $pos) : array { |
679 return $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos]; | 681 return $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos]; |
680 } | 682 } |
681 | 683 |
684 protected function getFloatCastKind(string $cast): int | |
685 { | |
686 $cast = strtolower($cast); | |
687 if (strpos($cast, 'float') !== false) { | |
688 return Double::KIND_FLOAT; | |
689 } | |
690 | |
691 if (strpos($cast, 'real') !== false) { | |
692 return Double::KIND_REAL; | |
693 } | |
694 | |
695 return Double::KIND_DOUBLE; | |
696 } | |
697 | |
682 protected function parseLNumber($str, $attributes, $allowInvalidOctal = false) { | 698 protected function parseLNumber($str, $attributes, $allowInvalidOctal = false) { |
683 try { | 699 try { |
684 return LNumber::fromString($str, $attributes, $allowInvalidOctal); | 700 return LNumber::fromString($str, $attributes, $allowInvalidOctal); |
685 } catch (Error $error) { | 701 } catch (Error $error) { |
686 $this->emitError($error); | 702 $this->emitError($error); |
706 if (!is_int($num)) { | 722 if (!is_int($num)) { |
707 return new String_($str, $attributes); | 723 return new String_($str, $attributes); |
708 } | 724 } |
709 | 725 |
710 return new LNumber($num, $attributes); | 726 return new LNumber($num, $attributes); |
727 } | |
728 | |
729 protected function stripIndentation( | |
730 string $string, int $indentLen, string $indentChar, | |
731 bool $newlineAtStart, bool $newlineAtEnd, array $attributes | |
732 ) { | |
733 if ($indentLen === 0) { | |
734 return $string; | |
735 } | |
736 | |
737 $start = $newlineAtStart ? '(?:(?<=\n)|\A)' : '(?<=\n)'; | |
738 $end = $newlineAtEnd ? '(?:(?=[\r\n])|\z)' : '(?=[\r\n])'; | |
739 $regex = '/' . $start . '([ \t]*)(' . $end . ')?/'; | |
740 return preg_replace_callback( | |
741 $regex, | |
742 function ($matches) use ($indentLen, $indentChar, $attributes) { | |
743 $prefix = substr($matches[1], 0, $indentLen); | |
744 if (false !== strpos($prefix, $indentChar === " " ? "\t" : " ")) { | |
745 $this->emitError(new Error( | |
746 'Invalid indentation - tabs and spaces cannot be mixed', $attributes | |
747 )); | |
748 } elseif (strlen($prefix) < $indentLen && !isset($matches[2])) { | |
749 $this->emitError(new Error( | |
750 'Invalid body indentation level ' . | |
751 '(expecting an indentation level of at least ' . $indentLen . ')', | |
752 $attributes | |
753 )); | |
754 } | |
755 return substr($matches[0], strlen($prefix)); | |
756 }, | |
757 $string | |
758 ); | |
759 } | |
760 | |
761 protected function parseDocString( | |
762 string $startToken, $contents, string $endToken, | |
763 array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape | |
764 ) { | |
765 $kind = strpos($startToken, "'") === false | |
766 ? String_::KIND_HEREDOC : String_::KIND_NOWDOC; | |
767 | |
768 $regex = '/\A[bB]?<<<[ \t]*[\'"]?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[\'"]?(?:\r\n|\n|\r)\z/'; | |
769 $result = preg_match($regex, $startToken, $matches); | |
770 assert($result === 1); | |
771 $label = $matches[1]; | |
772 | |
773 $result = preg_match('/\A[ \t]*/', $endToken, $matches); | |
774 assert($result === 1); | |
775 $indentation = $matches[0]; | |
776 | |
777 $attributes['kind'] = $kind; | |
778 $attributes['docLabel'] = $label; | |
779 $attributes['docIndentation'] = $indentation; | |
780 | |
781 $indentHasSpaces = false !== strpos($indentation, " "); | |
782 $indentHasTabs = false !== strpos($indentation, "\t"); | |
783 if ($indentHasSpaces && $indentHasTabs) { | |
784 $this->emitError(new Error( | |
785 'Invalid indentation - tabs and spaces cannot be mixed', | |
786 $endTokenAttributes | |
787 )); | |
788 | |
789 // Proceed processing as if this doc string is not indented | |
790 $indentation = ''; | |
791 } | |
792 | |
793 $indentLen = \strlen($indentation); | |
794 $indentChar = $indentHasSpaces ? " " : "\t"; | |
795 | |
796 if (\is_string($contents)) { | |
797 if ($contents === '') { | |
798 return new String_('', $attributes); | |
799 } | |
800 | |
801 $contents = $this->stripIndentation( | |
802 $contents, $indentLen, $indentChar, true, true, $attributes | |
803 ); | |
804 $contents = preg_replace('~(\r\n|\n|\r)\z~', '', $contents); | |
805 | |
806 if ($kind === String_::KIND_HEREDOC) { | |
807 $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape); | |
808 } | |
809 | |
810 return new String_($contents, $attributes); | |
811 } else { | |
812 assert(count($contents) > 0); | |
813 if (!$contents[0] instanceof Node\Scalar\EncapsedStringPart) { | |
814 // If there is no leading encapsed string part, pretend there is an empty one | |
815 $this->stripIndentation( | |
816 '', $indentLen, $indentChar, true, false, $contents[0]->getAttributes() | |
817 ); | |
818 } | |
819 | |
820 $newContents = []; | |
821 foreach ($contents as $i => $part) { | |
822 if ($part instanceof Node\Scalar\EncapsedStringPart) { | |
823 $isLast = $i === \count($contents) - 1; | |
824 $part->value = $this->stripIndentation( | |
825 $part->value, $indentLen, $indentChar, | |
826 $i === 0, $isLast, $part->getAttributes() | |
827 ); | |
828 $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape); | |
829 if ($isLast) { | |
830 $part->value = preg_replace('~(\r\n|\n|\r)\z~', '', $part->value); | |
831 } | |
832 if ('' === $part->value) { | |
833 continue; | |
834 } | |
835 } | |
836 $newContents[] = $part; | |
837 } | |
838 return new Encapsed($newContents, $attributes); | |
839 } | |
711 } | 840 } |
712 | 841 |
713 protected function checkModifier($a, $b, $modifierPos) { | 842 protected function checkModifier($a, $b, $modifierPos) { |
714 // Jumping through some hoops here because verifyModifier() is also used elsewhere | 843 // Jumping through some hoops here because verifyModifier() is also used elsewhere |
715 try { | 844 try { |