annotate vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php @ 1:1a348b17ec81

Logo and header background
author Chris Cannam
date Thu, 30 Nov 2017 14:56:35 +0000
parents 4c8ae668cc8c
children 5fb285c0d0e3
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace PhpParser\Node\Scalar;
Chris@0 4
Chris@0 5 use PhpParser\Error;
Chris@0 6 use PhpParser\Node\Scalar;
Chris@0 7
Chris@0 8 class String_ extends Scalar
Chris@0 9 {
Chris@0 10 /* For use in "kind" attribute */
Chris@0 11 const KIND_SINGLE_QUOTED = 1;
Chris@0 12 const KIND_DOUBLE_QUOTED = 2;
Chris@0 13 const KIND_HEREDOC = 3;
Chris@0 14 const KIND_NOWDOC = 4;
Chris@0 15
Chris@0 16 /** @var string String value */
Chris@0 17 public $value;
Chris@0 18
Chris@0 19 protected static $replacements = array(
Chris@0 20 '\\' => '\\',
Chris@0 21 '$' => '$',
Chris@0 22 'n' => "\n",
Chris@0 23 'r' => "\r",
Chris@0 24 't' => "\t",
Chris@0 25 'f' => "\f",
Chris@0 26 'v' => "\v",
Chris@0 27 'e' => "\x1B",
Chris@0 28 );
Chris@0 29
Chris@0 30 /**
Chris@0 31 * Constructs a string scalar node.
Chris@0 32 *
Chris@0 33 * @param string $value Value of the string
Chris@0 34 * @param array $attributes Additional attributes
Chris@0 35 */
Chris@0 36 public function __construct($value, array $attributes = array()) {
Chris@0 37 parent::__construct($attributes);
Chris@0 38 $this->value = $value;
Chris@0 39 }
Chris@0 40
Chris@0 41 public function getSubNodeNames() {
Chris@0 42 return array('value');
Chris@0 43 }
Chris@0 44
Chris@0 45 /**
Chris@0 46 * @internal
Chris@0 47 *
Chris@0 48 * Parses a string token.
Chris@0 49 *
Chris@0 50 * @param string $str String token content
Chris@0 51 * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
Chris@0 52 *
Chris@0 53 * @return string The parsed string
Chris@0 54 */
Chris@0 55 public static function parse($str, $parseUnicodeEscape = true) {
Chris@0 56 $bLength = 0;
Chris@0 57 if ('b' === $str[0] || 'B' === $str[0]) {
Chris@0 58 $bLength = 1;
Chris@0 59 }
Chris@0 60
Chris@0 61 if ('\'' === $str[$bLength]) {
Chris@0 62 return str_replace(
Chris@0 63 array('\\\\', '\\\''),
Chris@0 64 array( '\\', '\''),
Chris@0 65 substr($str, $bLength + 1, -1)
Chris@0 66 );
Chris@0 67 } else {
Chris@0 68 return self::parseEscapeSequences(
Chris@0 69 substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape
Chris@0 70 );
Chris@0 71 }
Chris@0 72 }
Chris@0 73
Chris@0 74 /**
Chris@0 75 * @internal
Chris@0 76 *
Chris@0 77 * Parses escape sequences in strings (all string types apart from single quoted).
Chris@0 78 *
Chris@0 79 * @param string $str String without quotes
Chris@0 80 * @param null|string $quote Quote type
Chris@0 81 * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
Chris@0 82 *
Chris@0 83 * @return string String with escape sequences parsed
Chris@0 84 */
Chris@0 85 public static function parseEscapeSequences($str, $quote, $parseUnicodeEscape = true) {
Chris@0 86 if (null !== $quote) {
Chris@0 87 $str = str_replace('\\' . $quote, $quote, $str);
Chris@0 88 }
Chris@0 89
Chris@0 90 $extra = '';
Chris@0 91 if ($parseUnicodeEscape) {
Chris@0 92 $extra = '|u\{([0-9a-fA-F]+)\}';
Chris@0 93 }
Chris@0 94
Chris@0 95 return preg_replace_callback(
Chris@0 96 '~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~',
Chris@0 97 function($matches) {
Chris@0 98 $str = $matches[1];
Chris@0 99
Chris@0 100 if (isset(self::$replacements[$str])) {
Chris@0 101 return self::$replacements[$str];
Chris@0 102 } elseif ('x' === $str[0] || 'X' === $str[0]) {
Chris@0 103 return chr(hexdec($str));
Chris@0 104 } elseif ('u' === $str[0]) {
Chris@0 105 return self::codePointToUtf8(hexdec($matches[2]));
Chris@0 106 } else {
Chris@0 107 return chr(octdec($str));
Chris@0 108 }
Chris@0 109 },
Chris@0 110 $str
Chris@0 111 );
Chris@0 112 }
Chris@0 113
Chris@0 114 private static function codePointToUtf8($num) {
Chris@0 115 if ($num <= 0x7F) {
Chris@0 116 return chr($num);
Chris@0 117 }
Chris@0 118 if ($num <= 0x7FF) {
Chris@0 119 return chr(($num>>6) + 0xC0) . chr(($num&0x3F) + 0x80);
Chris@0 120 }
Chris@0 121 if ($num <= 0xFFFF) {
Chris@0 122 return chr(($num>>12) + 0xE0) . chr((($num>>6)&0x3F) + 0x80) . chr(($num&0x3F) + 0x80);
Chris@0 123 }
Chris@0 124 if ($num <= 0x1FFFFF) {
Chris@0 125 return chr(($num>>18) + 0xF0) . chr((($num>>12)&0x3F) + 0x80)
Chris@0 126 . chr((($num>>6)&0x3F) + 0x80) . chr(($num&0x3F) + 0x80);
Chris@0 127 }
Chris@0 128 throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large');
Chris@0 129 }
Chris@0 130
Chris@0 131 /**
Chris@0 132 * @internal
Chris@0 133 *
Chris@0 134 * Parses a constant doc string.
Chris@0 135 *
Chris@0 136 * @param string $startToken Doc string start token content (<<<SMTHG)
Chris@0 137 * @param string $str String token content
Chris@0 138 * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
Chris@0 139 *
Chris@0 140 * @return string Parsed string
Chris@0 141 */
Chris@0 142 public static function parseDocString($startToken, $str, $parseUnicodeEscape = true) {
Chris@0 143 // strip last newline (thanks tokenizer for sticking it into the string!)
Chris@0 144 $str = preg_replace('~(\r\n|\n|\r)\z~', '', $str);
Chris@0 145
Chris@0 146 // nowdoc string
Chris@0 147 if (false !== strpos($startToken, '\'')) {
Chris@0 148 return $str;
Chris@0 149 }
Chris@0 150
Chris@0 151 return self::parseEscapeSequences($str, null, $parseUnicodeEscape);
Chris@0 152 }
Chris@0 153 }