Mercurial > hg > soundsoftware-site
comparison vendor/gems/coderay-1.0.0/lib/coderay/scanners/php.rb @ 909:cbb26bc654de redmine-1.3
Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author | Chris Cannam |
---|---|
date | Fri, 24 Feb 2012 19:09:32 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
908:c6c2cbd0afee | 909:cbb26bc654de |
---|---|
1 module CodeRay | |
2 module Scanners | |
3 | |
4 load :html | |
5 | |
6 # Scanner for PHP. | |
7 # | |
8 # Original by Stefan Walk. | |
9 class PHP < Scanner | |
10 | |
11 register_for :php | |
12 file_extension 'php' | |
13 encoding 'BINARY' | |
14 | |
15 KINDS_NOT_LOC = HTML::KINDS_NOT_LOC | |
16 | |
17 protected | |
18 | |
19 def setup | |
20 @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true | |
21 end | |
22 | |
23 def reset_instance | |
24 super | |
25 @html_scanner.reset | |
26 end | |
27 | |
28 module Words # :nodoc: | |
29 | |
30 # according to http://www.php.net/manual/en/reserved.keywords.php | |
31 KEYWORDS = %w[ | |
32 abstract and array as break case catch class clone const continue declare default do else elseif | |
33 enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global | |
34 goto if implements interface instanceof namespace new or private protected public static switch | |
35 throw try use var while xor | |
36 cfunction old_function | |
37 ] | |
38 | |
39 TYPES = %w[ int integer float double bool boolean string array object resource ] | |
40 | |
41 LANGUAGE_CONSTRUCTS = %w[ | |
42 die echo empty exit eval include include_once isset list | |
43 require require_once return print unset | |
44 ] | |
45 | |
46 CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] | |
47 | |
48 # according to http://php.net/quickref.php on 2009-04-21; | |
49 # all functions with _ excluded (module functions) and selected additional functions | |
50 BUILTIN_FUNCTIONS = %w[ | |
51 abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 | |
52 atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec | |
53 bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite | |
54 calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog | |
55 compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex | |
56 decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each | |
57 ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract | |
58 fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner | |
59 fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv | |
60 fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate | |
61 getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid | |
62 getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext | |
63 gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate | |
64 gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell | |
65 gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate | |
66 implode include intval ip2long iptcembed iptcparse isset | |
67 jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp | |
68 juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log | |
69 log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort | |
70 natsort next ngettext nl2br nthmac octdec opendir openlog | |
71 ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow | |
72 prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile | |
73 readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir | |
74 serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget | |
75 snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat | |
76 strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen | |
77 strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn | |
78 strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam | |
79 textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack | |
80 unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap | |
81 array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc | |
82 array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip | |
83 array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey | |
84 array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad | |
85 array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift | |
86 array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect | |
87 array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk | |
88 array_walk_recursive | |
89 assert_options base_convert base64_decode base64_encode | |
90 chunk_split class_exists class_implements class_parents | |
91 count_chars debug_backtrace debug_print_backtrace debug_zval_dump | |
92 error_get_last error_log error_reporting extension_loaded | |
93 file_exists file_get_contents file_put_contents load_file | |
94 func_get_arg func_get_args func_num_args function_exists | |
95 get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars | |
96 get_current_user get_declared_classes get_declared_interfaces get_defined_constants | |
97 get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table | |
98 get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime | |
99 get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type | |
100 gc_collect_cycles gc_disable gc_enable gc_enabled | |
101 halt_compiler headers_list headers_sent highlight_file highlight_string | |
102 html_entity_decode htmlspecialchars_decode | |
103 in_array include_once inclued_get_data | |
104 is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite | |
105 is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable | |
106 is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file | |
107 is_writable is_writeable | |
108 locale_get_default locale_set_default | |
109 number_format override_function parse_str parse_url | |
110 php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name | |
111 php_strip_whitespace php_uname | |
112 preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace | |
113 preg_replace_callback preg_split print_r | |
114 require_once register_shutdown_function register_tick_function | |
115 set_error_handler set_exception_handler set_file_buffer set_include_path | |
116 set_magic_quotes_runtime set_time_limit shell_exec | |
117 str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count | |
118 strip_tags substr_compare substr_count substr_replace | |
119 time_nanosleep time_sleep_until | |
120 token_get_all token_name trigger_error | |
121 unregister_tick_function use_soap_error_handler user_error | |
122 utf8_decode utf8_encode var_dump var_export | |
123 version_compare | |
124 zend_logo_guid zend_thread_id zend_version | |
125 create_function call_user_func_array | |
126 posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid | |
127 posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups | |
128 posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid | |
129 posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid | |
130 posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod | |
131 posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid | |
132 posix_setuid posix_strerror posix_times posix_ttyname posix_uname | |
133 pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority | |
134 pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait | |
135 pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited | |
136 pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig | |
137 ] | |
138 # TODO: more built-in PHP functions? | |
139 | |
140 EXCEPTIONS = %w[ | |
141 E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING | |
142 E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT | |
143 ] | |
144 | |
145 CONSTANTS = %w[ | |
146 null true false self parent | |
147 __LINE__ __DIR__ __FILE__ __LINE__ | |
148 __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ | |
149 PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS | |
150 PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH | |
151 PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR | |
152 PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX | |
153 PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END | |
154 __COMPILER_HALT_OFFSET__ | |
155 EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS | |
156 EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL | |
157 COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED | |
158 CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 | |
159 M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES | |
160 CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB | |
161 HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS | |
162 INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP | |
163 CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT | |
164 STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX | |
165 LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 | |
166 ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 | |
167 ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 | |
168 MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT | |
169 ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING | |
170 POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES | |
171 N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR | |
172 YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN | |
173 LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 | |
174 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY | |
175 LOG_NDELAY LOG_NOWAIT LOG_PERROR | |
176 ] | |
177 | |
178 PREDEFINED = %w[ | |
179 $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV | |
180 $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header | |
181 $argc $argv | |
182 ] | |
183 | |
184 IDENT_KIND = WordList::CaseIgnoring.new(:ident). | |
185 add(KEYWORDS, :keyword). | |
186 add(TYPES, :predefined_type). | |
187 add(LANGUAGE_CONSTRUCTS, :keyword). | |
188 add(BUILTIN_FUNCTIONS, :predefined). | |
189 add(CLASSES, :predefined_constant). | |
190 add(EXCEPTIONS, :exception). | |
191 add(CONSTANTS, :predefined_constant) | |
192 | |
193 VARIABLE_KIND = WordList.new(:local_variable). | |
194 add(PREDEFINED, :predefined) | |
195 end | |
196 | |
197 module RE # :nodoc: | |
198 | |
199 PHP_START = / | |
200 <script\s+[^>]*?language\s*=\s*"php"[^>]*?> | | |
201 <script\s+[^>]*?language\s*=\s*'php'[^>]*?> | | |
202 <\?php\d? | | |
203 <\?(?!xml) | |
204 /xi | |
205 | |
206 PHP_END = %r! | |
207 </script> | | |
208 \?> | |
209 !xi | |
210 | |
211 HTML_INDICATOR = /<!DOCTYPE html|<(?:html|body|div|p)[> ]/i | |
212 | |
213 IDENTIFIER = /[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*/i | |
214 VARIABLE = /\$#{IDENTIFIER}/ | |
215 | |
216 OPERATOR = / | |
217 \.(?!\d)=? | # dot that is not decimal point, string concatenation | |
218 && | \|\| | # logic | |
219 :: | -> | => | # scope, member, dictionary | |
220 \\(?!\n) | # namespace | |
221 \+\+ | -- | # increment, decrement | |
222 [,;?:()\[\]{}] | # simple delimiters | |
223 [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts | |
224 [~$] | # whatever | |
225 =& | # reference assignment | |
226 [=!]=?=? | <> | # comparison and assignment | |
227 <<=? | >>=? | [<>]=? # comparison and shift | |
228 /x | |
229 | |
230 end | |
231 | |
232 protected | |
233 | |
234 def scan_tokens encoder, options | |
235 | |
236 if check(RE::PHP_START) || # starts with <? | |
237 (match?(/\s*<\S/) && check(/.{1,1000}#{RE::PHP_START}/om)) || # starts with tag and contains <? | |
238 check(/.{0,1000}#{RE::HTML_INDICATOR}/om) || | |
239 check(/.{1,100}#{RE::PHP_START}/om) # PHP start after max 100 chars | |
240 # is HTML with embedded PHP, so start with HTML | |
241 states = [:initial] | |
242 else | |
243 # is just PHP, so start with PHP surrounded by HTML | |
244 states = [:initial, :php] | |
245 end | |
246 | |
247 label_expected = true | |
248 case_expected = false | |
249 | |
250 heredoc_delimiter = nil | |
251 delimiter = nil | |
252 modifier = nil | |
253 | |
254 until eos? | |
255 | |
256 case states.last | |
257 | |
258 when :initial # HTML | |
259 if match = scan(RE::PHP_START) | |
260 encoder.text_token match, :inline_delimiter | |
261 label_expected = true | |
262 states << :php | |
263 else | |
264 match = scan_until(/(?=#{RE::PHP_START})/o) || scan_rest | |
265 @html_scanner.tokenize match unless match.empty? | |
266 end | |
267 | |
268 when :php | |
269 if match = scan(/\s+/) | |
270 encoder.text_token match, :space | |
271 | |
272 elsif match = scan(%r! (?m: \/\* (?: .*? \*\/ | .* ) ) | (?://|\#) .*? (?=#{RE::PHP_END}|$) !xo) | |
273 encoder.text_token match, :comment | |
274 | |
275 elsif match = scan(RE::IDENTIFIER) | |
276 kind = Words::IDENT_KIND[match] | |
277 if kind == :ident && label_expected && check(/:(?!:)/) | |
278 kind = :label | |
279 label_expected = true | |
280 else | |
281 label_expected = false | |
282 if kind == :ident && match =~ /^[A-Z]/ | |
283 kind = :constant | |
284 elsif kind == :keyword | |
285 case match | |
286 when 'class' | |
287 states << :class_expected | |
288 when 'function' | |
289 states << :function_expected | |
290 when 'case', 'default' | |
291 case_expected = true | |
292 end | |
293 elsif match == 'b' && check(/['"]/) # binary string literal | |
294 modifier = match | |
295 next | |
296 end | |
297 end | |
298 encoder.text_token match, kind | |
299 | |
300 elsif match = scan(/(?:\d+\.\d*|\d*\.\d+)(?:e[-+]?\d+)?|\d+e[-+]?\d+/i) | |
301 label_expected = false | |
302 encoder.text_token match, :float | |
303 | |
304 elsif match = scan(/0x[0-9a-fA-F]+/) | |
305 label_expected = false | |
306 encoder.text_token match, :hex | |
307 | |
308 elsif match = scan(/\d+/) | |
309 label_expected = false | |
310 encoder.text_token match, :integer | |
311 | |
312 elsif match = scan(/['"`]/) | |
313 encoder.begin_group :string | |
314 if modifier | |
315 encoder.text_token modifier, :modifier | |
316 modifier = nil | |
317 end | |
318 delimiter = match | |
319 encoder.text_token match, :delimiter | |
320 states.push match == "'" ? :sqstring : :dqstring | |
321 | |
322 elsif match = scan(RE::VARIABLE) | |
323 label_expected = false | |
324 encoder.text_token match, Words::VARIABLE_KIND[match] | |
325 | |
326 elsif match = scan(/\{/) | |
327 encoder.text_token match, :operator | |
328 label_expected = true | |
329 states.push :php | |
330 | |
331 elsif match = scan(/\}/) | |
332 if states.size == 1 | |
333 encoder.text_token match, :error | |
334 else | |
335 states.pop | |
336 if states.last.is_a?(::Array) | |
337 delimiter = states.last[1] | |
338 states[-1] = states.last[0] | |
339 encoder.text_token match, :delimiter | |
340 encoder.end_group :inline | |
341 else | |
342 encoder.text_token match, :operator | |
343 label_expected = true | |
344 end | |
345 end | |
346 | |
347 elsif match = scan(/@/) | |
348 label_expected = false | |
349 encoder.text_token match, :exception | |
350 | |
351 elsif match = scan(RE::PHP_END) | |
352 encoder.text_token match, :inline_delimiter | |
353 states = [:initial] | |
354 | |
355 elsif match = scan(/<<<(?:(#{RE::IDENTIFIER})|"(#{RE::IDENTIFIER})"|'(#{RE::IDENTIFIER})')/o) | |
356 encoder.begin_group :string | |
357 # warn 'heredoc in heredoc?' if heredoc_delimiter | |
358 heredoc_delimiter = Regexp.escape(self[1] || self[2] || self[3]) | |
359 encoder.text_token match, :delimiter | |
360 states.push self[3] ? :sqstring : :dqstring | |
361 heredoc_delimiter = /#{heredoc_delimiter}(?=;?$)/ | |
362 | |
363 elsif match = scan(/#{RE::OPERATOR}/o) | |
364 label_expected = match == ';' | |
365 if case_expected | |
366 label_expected = true if match == ':' | |
367 case_expected = false | |
368 end | |
369 encoder.text_token match, :operator | |
370 | |
371 else | |
372 encoder.text_token getch, :error | |
373 | |
374 end | |
375 | |
376 when :sqstring | |
377 if match = scan(heredoc_delimiter ? /[^\\\n]+/ : /[^'\\]+/) | |
378 encoder.text_token match, :content | |
379 elsif !heredoc_delimiter && match = scan(/'/) | |
380 encoder.text_token match, :delimiter | |
381 encoder.end_group :string | |
382 delimiter = nil | |
383 label_expected = false | |
384 states.pop | |
385 elsif heredoc_delimiter && match = scan(/\n/) | |
386 if scan heredoc_delimiter | |
387 encoder.text_token "\n", :content | |
388 encoder.text_token matched, :delimiter | |
389 encoder.end_group :string | |
390 heredoc_delimiter = nil | |
391 label_expected = false | |
392 states.pop | |
393 else | |
394 encoder.text_token match, :content | |
395 end | |
396 elsif match = scan(heredoc_delimiter ? /\\\\/ : /\\[\\'\n]/) | |
397 encoder.text_token match, :char | |
398 elsif match = scan(/\\./m) | |
399 encoder.text_token match, :content | |
400 elsif match = scan(/\\/) | |
401 encoder.text_token match, :error | |
402 else | |
403 states.pop | |
404 end | |
405 | |
406 when :dqstring | |
407 if match = scan(heredoc_delimiter ? /[^${\\\n]+/ : (delimiter == '"' ? /[^"${\\]+/ : /[^`${\\]+/)) | |
408 encoder.text_token match, :content | |
409 elsif !heredoc_delimiter && match = scan(delimiter == '"' ? /"/ : /`/) | |
410 encoder.text_token match, :delimiter | |
411 encoder.end_group :string | |
412 delimiter = nil | |
413 label_expected = false | |
414 states.pop | |
415 elsif heredoc_delimiter && match = scan(/\n/) | |
416 if scan heredoc_delimiter | |
417 encoder.text_token "\n", :content | |
418 encoder.text_token matched, :delimiter | |
419 encoder.end_group :string | |
420 heredoc_delimiter = nil | |
421 label_expected = false | |
422 states.pop | |
423 else | |
424 encoder.text_token match, :content | |
425 end | |
426 elsif match = scan(/\\(?:x[0-9A-Fa-f]{1,2}|[0-7]{1,3})/) | |
427 encoder.text_token match, :char | |
428 elsif match = scan(heredoc_delimiter ? /\\[nrtvf\\$]/ : (delimiter == '"' ? /\\[nrtvf\\$"]/ : /\\[nrtvf\\$`]/)) | |
429 encoder.text_token match, :char | |
430 elsif match = scan(/\\./m) | |
431 encoder.text_token match, :content | |
432 elsif match = scan(/\\/) | |
433 encoder.text_token match, :error | |
434 elsif match = scan(/#{RE::VARIABLE}/o) | |
435 if check(/\[#{RE::IDENTIFIER}\]/o) | |
436 encoder.begin_group :inline | |
437 encoder.text_token match, :local_variable | |
438 encoder.text_token scan(/\[/), :operator | |
439 encoder.text_token scan(/#{RE::IDENTIFIER}/o), :ident | |
440 encoder.text_token scan(/\]/), :operator | |
441 encoder.end_group :inline | |
442 elsif check(/\[/) | |
443 match << scan(/\[['"]?#{RE::IDENTIFIER}?['"]?\]?/o) | |
444 encoder.text_token match, :error | |
445 elsif check(/->#{RE::IDENTIFIER}/o) | |
446 encoder.begin_group :inline | |
447 encoder.text_token match, :local_variable | |
448 encoder.text_token scan(/->/), :operator | |
449 encoder.text_token scan(/#{RE::IDENTIFIER}/o), :ident | |
450 encoder.end_group :inline | |
451 elsif check(/->/) | |
452 match << scan(/->/) | |
453 encoder.text_token match, :error | |
454 else | |
455 encoder.text_token match, :local_variable | |
456 end | |
457 elsif match = scan(/\{/) | |
458 if check(/\$/) | |
459 encoder.begin_group :inline | |
460 states[-1] = [states.last, delimiter] | |
461 delimiter = nil | |
462 states.push :php | |
463 encoder.text_token match, :delimiter | |
464 else | |
465 encoder.text_token match, :content | |
466 end | |
467 elsif match = scan(/\$\{#{RE::IDENTIFIER}\}/o) | |
468 encoder.text_token match, :local_variable | |
469 elsif match = scan(/\$/) | |
470 encoder.text_token match, :content | |
471 else | |
472 states.pop | |
473 end | |
474 | |
475 when :class_expected | |
476 if match = scan(/\s+/) | |
477 encoder.text_token match, :space | |
478 elsif match = scan(/#{RE::IDENTIFIER}/o) | |
479 encoder.text_token match, :class | |
480 states.pop | |
481 else | |
482 states.pop | |
483 end | |
484 | |
485 when :function_expected | |
486 if match = scan(/\s+/) | |
487 encoder.text_token match, :space | |
488 elsif match = scan(/&/) | |
489 encoder.text_token match, :operator | |
490 elsif match = scan(/#{RE::IDENTIFIER}/o) | |
491 encoder.text_token match, :function | |
492 states.pop | |
493 else | |
494 states.pop | |
495 end | |
496 | |
497 else | |
498 raise_inspect 'Unknown state!', encoder, states | |
499 end | |
500 | |
501 end | |
502 | |
503 encoder | |
504 end | |
505 | |
506 end | |
507 | |
508 end | |
509 end |