Original by Stefan Walk.
# File lib/coderay/scanners/php.rb, line 18 18: def reset_instance 19: super 20: @html_scanner.reset 21: end
# File lib/coderay/scanners/php.rb, line 227 227: def scan_tokens tokens, options 228: 229: if check(RE::PHP_START) || # starts with <? 230: (match?(/\s*<\S/) && exist?(RE::PHP_START)) || # starts with tag and contains <? 231: exist?(RE::HTML_INDICATOR) || 232: check(/.{1,100}#{RE::PHP_START}/m) # PHP start after max 100 chars 233: # is HTML with embedded PHP, so start with HTML 234: states = [:initial] 235: else 236: # is just PHP, so start with PHP surrounded by HTML 237: states = [:initial, :php] 238: end 239: 240: label_expected = true 241: case_expected = false 242: 243: heredoc_delimiter = nil 244: delimiter = nil 245: modifier = nil 246: 247: until eos? 248: 249: match = nil 250: kind = nil 251: 252: case states.last 253: 254: when :initial # HTML 255: if scan RE::PHP_START 256: kind = :inline_delimiter 257: label_expected = true 258: states << :php 259: else 260: match = scan_until(/(?=#{RE::PHP_START})/) || scan_until(/\z/) 261: @html_scanner.tokenize match unless match.empty? 262: next 263: end 264: 265: when :php 266: if match = scan(/\s+/) 267: tokens << [match, :space] 268: next 269: 270: elsif scan(% (?m: \/\* (?: .*? \*\/ | .* ) ) | (?://|\#) .*? (?=#{RE::PHP_END}|$) !o) 271: kind = :comment 272: 273: elsif match = scan(RE::IDENTIFIER) 274: kind = Words::IDENT_KIND[match] 275: if kind == :ident && label_expected && check(/:(?!:)/) 276: kind = :label 277: label_expected = true 278: else 279: label_expected = false 280: if kind == :ident && match =~ /^[A-Z]/ 281: kind = :constant 282: elsif kind == :reserved 283: case match 284: when 'class' 285: states << :class_expected 286: when 'function' 287: states << :function_expected 288: when 'case', 'default' 289: case_expected = true 290: end 291: elsif match == 'b' && check(/['"]/) # binary string literal 292: modifier = match 293: next 294: end 295: end 296: 297: elsif scan(/(?:\d+\.\d*|\d*\.\d+)(?:e[-+]?\d+)?|\d+e[-+]?\d+/) 298: label_expected = false 299: kind = :float 300: 301: elsif scan(/0x[0-9a-fA-F]+/) 302: label_expected = false 303: kind = :hex 304: 305: elsif scan(/\d+/) 306: label_expected = false 307: kind = :integer 308: 309: elsif scan(/'/) 310: tokens << [:open, :string] 311: if modifier 312: tokens << [modifier, :modifier] 313: modifier = nil 314: end 315: kind = :delimiter 316: states.push :sqstring 317: 318: elsif match = scan(/["`]/) 319: tokens << [:open, :string] 320: if modifier 321: tokens << [modifier, :modifier] 322: modifier = nil 323: end 324: delimiter = match 325: kind = :delimiter 326: states.push :dqstring 327: 328: elsif match = scan(RE::VARIABLE) 329: label_expected = false 330: kind = Words::VARIABLE_KIND[match] 331: 332: elsif scan(/\{/) 333: kind = :operator 334: label_expected = true 335: states.push :php 336: 337: elsif scan(/\}/) 338: if states.size == 1 339: kind = :error 340: else 341: states.pop 342: if states.last.is_a?(::Array) 343: delimiter = states.last[1] 344: states[1] = states.last[0] 345: tokens << [matched, :delimiter] 346: tokens << [:close, :inline] 347: next 348: else 349: kind = :operator 350: label_expected = true 351: end 352: end 353: 354: elsif scan(/@/) 355: label_expected = false 356: kind = :exception 357: 358: elsif scan RE::PHP_END 359: kind = :inline_delimiter 360: states = [:initial] 361: 362: elsif match = scan(/<<<(?:(#{RE::IDENTIFIER})|"(#{RE::IDENTIFIER})"|'(#{RE::IDENTIFIER})')/) 363: tokens << [:open, :string] 364: warn 'heredoc in heredoc?' if heredoc_delimiter 365: heredoc_delimiter = Regexp.escape(self[1] || self[2] || self[3]) 366: kind = :delimiter 367: states.push self[3] ? :sqstring : :dqstring 368: heredoc_delimiter = /#{heredoc_delimiter}(?=;?$)/ 369: 370: elsif match = scan(/#{RE::OPERATOR}/) 371: label_expected = match == ';' 372: if case_expected 373: label_expected = true if match == ':' 374: case_expected = false 375: end 376: kind = :operator 377: 378: else 379: getch 380: kind = :error 381: 382: end 383: 384: when :sqstring 385: if scan(heredoc_delimiter ? /[^\\\n]+/ : /[^'\\]+/) 386: kind = :content 387: elsif !heredoc_delimiter && scan(/'/) 388: tokens << [matched, :delimiter] 389: tokens << [:close, :string] 390: delimiter = nil 391: label_expected = false 392: states.pop 393: next 394: elsif heredoc_delimiter && match = scan(/\n/) 395: kind = :content 396: if scan heredoc_delimiter 397: tokens << ["\n", :content] 398: tokens << [matched, :delimiter] 399: tokens << [:close, :string] 400: heredoc_delimiter = nil 401: label_expected = false 402: states.pop 403: next 404: end 405: elsif scan(heredoc_delimiter ? /\\\\/ : /\\[\\'\n]/) 406: kind = :char 407: elsif scan(/\\./) 408: kind = :content 409: elsif scan(/\\/) 410: kind = :error 411: end 412: 413: when :dqstring 414: if scan(heredoc_delimiter ? /[^${\\\n]+/ : (delimiter == '"' ? /[^"${\\]+/ : /[^`${\\]+/)) 415: kind = :content 416: elsif !heredoc_delimiter && scan(delimiter == '"' ? /"/ : /`/) 417: tokens << [matched, :delimiter] 418: tokens << [:close, :string] 419: delimiter = nil 420: label_expected = false 421: states.pop 422: next 423: elsif heredoc_delimiter && match = scan(/\n/) 424: kind = :content 425: if scan heredoc_delimiter 426: tokens << ["\n", :content] 427: tokens << [matched, :delimiter] 428: tokens << [:close, :string] 429: heredoc_delimiter = nil 430: label_expected = false 431: states.pop 432: next 433: end 434: elsif scan(/\\(?:x[0-9A-Fa-f]{1,2}|[0-7]{1,3})/) 435: kind = :char 436: elsif scan(heredoc_delimiter ? /\\[nrtvf\\$]/ : (delimiter == '"' ? /\\[nrtvf\\$"]/ : /\\[nrtvf\\$`]/)) 437: kind = :char 438: elsif scan(/\\./) 439: kind = :content 440: elsif scan(/\\/) 441: kind = :error 442: elsif match = scan(/#{RE::VARIABLE}/) 443: kind = :local_variable 444: if check(/\[#{RE::IDENTIFIER}\]/) 445: tokens << [:open, :inline] 446: tokens << [match, :local_variable] 447: tokens << [scan(/\[/), :operator] 448: tokens << [scan(/#{RE::IDENTIFIER}/), :ident] 449: tokens << [scan(/\]/), :operator] 450: tokens << [:close, :inline] 451: next 452: elsif check(/\[/) 453: match << scan(/\[['"]?#{RE::IDENTIFIER}?['"]?\]?/) 454: kind = :error 455: elsif check(/->#{RE::IDENTIFIER}/) 456: tokens << [:open, :inline] 457: tokens << [match, :local_variable] 458: tokens << [scan(/->/), :operator] 459: tokens << [scan(/#{RE::IDENTIFIER}/), :ident] 460: tokens << [:close, :inline] 461: next 462: elsif check(/->/) 463: match << scan(/->/) 464: kind = :error 465: end 466: elsif match = scan(/\{/) 467: if check(/\$/) 468: kind = :delimiter 469: states[1] = [states.last, delimiter] 470: delimiter = nil 471: states.push :php 472: tokens << [:open, :inline] 473: else 474: kind = :string 475: end 476: elsif scan(/\$\{#{RE::IDENTIFIER}\}/) 477: kind = :local_variable 478: elsif scan(/\$/) 479: kind = :content 480: end 481: 482: when :class_expected 483: if scan(/\s+/) 484: kind = :space 485: elsif match = scan(/#{RE::IDENTIFIER}/) 486: kind = :class 487: states.pop 488: else 489: states.pop 490: next 491: end 492: 493: when :function_expected 494: if scan(/\s+/) 495: kind = :space 496: elsif scan(/&/) 497: kind = :operator 498: elsif match = scan(/#{RE::IDENTIFIER}/) 499: kind = :function 500: states.pop 501: else 502: states.pop 503: next 504: end 505: 506: else 507: raise_inspect 'Unknown state!', tokens, states 508: end 509: 510: match ||= matched 511: if $CODERAY_DEBUG and not kind 512: raise_inspect 'Error token %p in line %d' % 513: [[match, kind], line], tokens, states 514: end 515: raise_inspect 'Empty token', tokens, states unless match 516: 517: tokens << [match, kind] 518: 519: end 520: 521: tokens 522: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.