1<?php 2/** 3 * An element (token) generated by the scan 4 * 5 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 6 * @copyright Copyright 2010-2014 PhpCss Team 7 */ 8 9namespace PhpCss\Scanner { 10 11 use BadMethodCallException; 12 use InvalidArgumentException; 13 14 /** 15 * An element (token) generated by the scan 16 * 17 * @property-read integer $type 18 * @property-read string $content 19 * @property-read integer $length 20 * @property-read integer $position 21 */ 22 class Token { 23 24 // special any token (a joker) 25 public const ANY = 255; 26 27 //whitespace 28 public const WHITESPACE = 1; 29 public const NUMBER = 2; 30 public const IDENTIFIER = 3; 31 32 //simple selectors 33 public const CLASS_SELECTOR = 11; 34 public const ID_SELECTOR = 12; 35 public const PSEUDO_CLASS = 13; 36 public const PSEUDO_CLASS_POSITION = 14; 37 public const PSEUDO_ELEMENT = 15; 38 39 // attribute selectors - [...] 40 public const ATTRIBUTE_SELECTOR_START = 20; 41 public const ATTRIBUTE_SELECTOR_END = 21; 42 public const ATTRIBUTE_OPERATOR = 22; 43 44 // parentheses - (...) 45 public const PARENTHESES_START = 31; 46 public const PARENTHESES_END = 32; 47 48 //selector separator 49 public const COMBINATOR = 41; 50 public const SEPARATOR = 42; 51 52 //single quoted strings 53 public const SINGLEQUOTE_STRING_START = 100; 54 public const SINGLEQUOTE_STRING_END = 101; 55 // double quoted strings 56 public const DOUBLEQUOTE_STRING_START = 102; 57 public const DOUBLEQUOTE_STRING_END = 103; 58 // string general 59 public const STRING_CHARACTERS = 110; 60 public const STRING_ESCAPED_CHARACTER = 111; 61 62 private static $_names = [ 63 self::ANY => 'ANY', 64 self::WHITESPACE => 'WHITESPACE', 65 self::NUMBER => 'NUMBER', 66 self::IDENTIFIER => 'IDENTIFIER', 67 self::CLASS_SELECTOR => 'SIMPLESELECTOR_CLASS', 68 self::ID_SELECTOR => 'SIMPLE_SELECTOR_ID', 69 self::PSEUDO_CLASS => 'PSEUDOCLASS', 70 self::PSEUDO_CLASS_POSITION => 'PSEUDOCLASS_POSITION', 71 self::PSEUDO_ELEMENT => 'PSEUDOELEMENT', 72 self::ATTRIBUTE_SELECTOR_START => 'SIMPLESELECTOR_ATTRIBUTE_START', 73 self::ATTRIBUTE_SELECTOR_END => 'SIMPLESELECTOR_ATTRIBUTE_END', 74 self::ATTRIBUTE_OPERATOR => 'SIMPLESELECTOR_ATTRIBUTE_OPERATOR', 75 self::PARENTHESES_START => 'PARENTHESES_START', 76 self::PARENTHESES_END => 'PARENTHESES_END', 77 self::COMBINATOR => 'SELECTOR_COMBINATOR', 78 self::SEPARATOR => 'SELECTOR_SEPARATOR', 79 self::SINGLEQUOTE_STRING_START => 'STRING_SINGLE_QUOTE_START', 80 self::SINGLEQUOTE_STRING_END => 'STRING_SINGLE_QUOTE_END', 81 self::DOUBLEQUOTE_STRING_START => 'STRING_DOUBLE_QUOTE_START', 82 self::DOUBLEQUOTE_STRING_END => 'STRING_DOUBLE_QUOTE_END', 83 self::STRING_CHARACTERS => 'STRING_CHARACTERS', 84 self::STRING_ESCAPED_CHARACTER => 'STRING_ESCAPED_CHARACTER', 85 ]; 86 87 /** 88 * Token type 89 * @var integer 90 */ 91 private $_type; 92 /** 93 * Token string content 94 * @var string 95 */ 96 private $_content; 97 /** 98 * Token string content length 99 * @var integer 100 */ 101 private $_length; 102 /** 103 * Byte position the token was found at 104 * @var integer 105 */ 106 private $_position; 107 108 /** 109 * Construct and initialize token 110 * 111 * @param integer $type 112 * @param string $content 113 * @param integer $position 114 */ 115 public function __construct(int $type = 0, string $content = '', int $position = -1) { 116 $this->_type = $type; 117 $this->_content = $content; 118 $this->_length = strlen($content); 119 $this->_position = $position; 120 } 121 122 /** 123 * Get token attribute 124 * 125 * @param string $name 126 * @return int|string 127 * @throws InvalidArgumentException 128 */ 129 public function __get(string $name) { 130 switch ($name) { 131 case 'type' : 132 return $this->_type; 133 case 'content' : 134 return $this->_content; 135 case 'length' : 136 return $this->_length; 137 case 'position' : 138 return $this->_position; 139 } 140 throw new InvalidArgumentException(); 141 } 142 143 /** 144 * Has token property 145 * 146 * @param string $name 147 * @return bool 148 */ 149 public function __isset(string $name): bool { 150 switch ($name) { 151 case 'type' : 152 case 'content' : 153 case 'length' : 154 case 'position' : 155 return TRUE; 156 } 157 return FALSE; 158 } 159 160 /** 161 * Do not allow to set attributes 162 * 163 * @param string $name 164 * @param mixed $value 165 * @return void 166 * @throws BadMethodCallException 167 */ 168 public function __set(string $name, $value): void { 169 throw new BadMethodCallException(); 170 } 171 172 /** 173 * Convert token object to string 174 * @return string 175 */ 176 public function __toString() { 177 return 'TOKEN::'.self::typeToString($this->type). 178 ' @'.$this->position.' '.$this->quoteContent($this->content); 179 } 180 181 /** 182 * Return string representation of token type 183 * 184 * @param integer $type 185 * @return string 186 */ 187 public static function typeToString(int $type): string { 188 return self::$_names[$type]; 189 } 190 191 /** 192 * Escape content for double quoted, single line string representation 193 * 194 * @param string $content 195 * @return string 196 */ 197 protected function quoteContent(string $content): string { 198 return "'".str_replace( 199 ['\\', "\r", "\n", "'"], 200 ['\\\\', '\\r', '\\n', "\\'"], 201 $content 202 )."'"; 203 } 204 } 205} 206