Original by Stefan Walk.
Methods
Classes and Modules
Module CodeRay::Scanners::PHP::REModule CodeRay::Scanners::PHP::Words
Constants
| KINDS_NOT_LOC | = | HTML::KINDS_NOT_LOC |
Public Instance methods
# File lib/coderay/scanners/php.rb, line 18 def reset_instance super @html_scanner.reset end
# File lib/coderay/scanners/php.rb, line 227 def scan_tokens tokens, options if check(RE::PHP_START) || # starts with <? (match?(/\s*<\S/) && exist?(RE::PHP_START)) || # starts with tag and contains <? exist?(RE::HTML_INDICATOR) || check(/.{1,100}#{RE::PHP_START}/om) # PHP start after max 100 chars # is HTML with embedded PHP, so start with HTML states = [:initial] else # is just PHP, so start with PHP surrounded by HTML states = [:initial, :php] end label_expected = true case_expected = false heredoc_delimiter = nil delimiter = nil modifier = nil until eos? match = nil kind = nil case states.last when :initial # HTML if scan RE::PHP_START kind = :inline_delimiter label_expected = true states << :php else match = scan_until(/(?=#{RE::PHP_START})/o) || scan_until(/\z/) @html_scanner.tokenize match unless match.empty? next end when :php if match = scan(/\s+/) tokens << [match, :space] next elsif scan(%r! (?m: \/\* (?: .*? \*\/ | .* ) ) | (?://|\#) .*? (?=#{RE::PHP_END}|$) !xo) kind = :comment elsif match = scan(RE::IDENTIFIER) kind = Words::IDENT_KIND[match] if kind == :ident && label_expected && check(/:(?!:)/) kind = :label label_expected = true else label_expected = false if kind == :ident && match =~ /^[A-Z]/ kind = :constant elsif kind == :reserved case match when 'class' states << :class_expected when 'function' states << :function_expected when 'case', 'default' case_expected = true end elsif match == 'b' && check(/['"]/) # binary string literal modifier = match next end end elsif scan(/(?:\d+\.\d*|\d*\.\d+)(?:e[-+]?\d+)?|\d+e[-+]?\d+/i) label_expected = false kind = :float elsif scan(/0x[0-9a-fA-F]+/) label_expected = false kind = :hex elsif scan(/\d+/) label_expected = false kind = :integer elsif scan(/'/) tokens << [:open, :string] if modifier tokens << [modifier, :modifier] modifier = nil end kind = :delimiter states.push :sqstring elsif match = scan(/["`]/) tokens << [:open, :string] if modifier tokens << [modifier, :modifier] modifier = nil end delimiter = match kind = :delimiter states.push :dqstring elsif match = scan(RE::VARIABLE) label_expected = false kind = Words::VARIABLE_KIND[match] elsif scan(/\{/) kind = :operator label_expected = true states.push :php elsif scan(/\}/) if states.size == 1 kind = :error else states.pop if states.last.is_a?(::Array) delimiter = states.last[1] states[-1] = states.last[0] tokens << [matched, :delimiter] tokens << [:close, :inline] next else kind = :operator label_expected = true end end elsif scan(/@/) label_expected = false kind = :exception elsif scan RE::PHP_END kind = :inline_delimiter states = [:initial] elsif match = scan(/<<<(?:(#{RE::IDENTIFIER})|"(#{RE::IDENTIFIER})"|'(#{RE::IDENTIFIER})')/o) tokens << [:open, :string] warn 'heredoc in heredoc?' if heredoc_delimiter heredoc_delimiter = Regexp.escape(self[1] || self[2] || self[3]) kind = :delimiter states.push self[3] ? :sqstring : :dqstring heredoc_delimiter = /#{heredoc_delimiter}(?=;?$)/ elsif match = scan(/#{RE::OPERATOR}/o) label_expected = match == ';' if case_expected label_expected = true if match == ':' case_expected = false end kind = :operator else getch kind = :error end when :sqstring if scan(heredoc_delimiter ? /[^\\\n]+/ : /[^'\\]+/) kind = :content elsif !heredoc_delimiter && scan(/'/) tokens << [matched, :delimiter] tokens << [:close, :string] delimiter = nil label_expected = false states.pop next elsif heredoc_delimiter && match = scan(/\n/) kind = :content if scan heredoc_delimiter tokens << ["\n", :content] tokens << [matched, :delimiter] tokens << [:close, :string] heredoc_delimiter = nil label_expected = false states.pop next end elsif scan(heredoc_delimiter ? /\\\\/ : /\\[\\'\n]/) kind = :char elsif scan(/\\./m) kind = :content elsif scan(/\\/) kind = :error end when :dqstring if scan(heredoc_delimiter ? /[^${\\\n]+/ : (delimiter == '"' ? /[^"${\\]+/ : /[^`${\\]+/)) kind = :content elsif !heredoc_delimiter && scan(delimiter == '"' ? /"/ : /`/) tokens << [matched, :delimiter] tokens << [:close, :string] delimiter = nil label_expected = false states.pop next elsif heredoc_delimiter && match = scan(/\n/) kind = :content if scan heredoc_delimiter tokens << ["\n", :content] tokens << [matched, :delimiter] tokens << [:close, :string] heredoc_delimiter = nil label_expected = false states.pop next end elsif scan(/\\(?:x[0-9A-Fa-f]{1,2}|[0-7]{1,3})/) kind = :char elsif scan(heredoc_delimiter ? /\\[nrtvf\\$]/ : (delimiter == '"' ? /\\[nrtvf\\$"]/ : /\\[nrtvf\\$`]/)) kind = :char elsif scan(/\\./m) kind = :content elsif scan(/\\/) kind = :error elsif match = scan(/#{RE::VARIABLE}/o) kind = :local_variable if check(/\[#{RE::IDENTIFIER}\]/o) tokens << [:open, :inline] tokens << [match, :local_variable] tokens << [scan(/\[/), :operator] tokens << [scan(/#{RE::IDENTIFIER}/o), :ident] tokens << [scan(/\]/), :operator] tokens << [:close, :inline] next elsif check(/\[/) match << scan(/\[['"]?#{RE::IDENTIFIER}?['"]?\]?/o) kind = :error elsif check(/->#{RE::IDENTIFIER}/o) tokens << [:open, :inline] tokens << [match, :local_variable] tokens << [scan(/->/), :operator] tokens << [scan(/#{RE::IDENTIFIER}/o), :ident] tokens << [:close, :inline] next elsif check(/->/) match << scan(/->/) kind = :error end elsif match = scan(/\{/) if check(/\$/) kind = :delimiter states[-1] = [states.last, delimiter] delimiter = nil states.push :php tokens << [:open, :inline] else kind = :string end elsif scan(/\$\{#{RE::IDENTIFIER}\}/o) kind = :local_variable elsif scan(/\$/) kind = :content end when :class_expected if scan(/\s+/) kind = :space elsif match = scan(/#{RE::IDENTIFIER}/o) kind = :class states.pop else states.pop next end when :function_expected if scan(/\s+/) kind = :space elsif scan(/&/) kind = :operator elsif match = scan(/#{RE::IDENTIFIER}/o) kind = :function states.pop else states.pop next end else raise_inspect 'Unknown state!', tokens, states end match ||= matched if $CODERAY_DEBUG and not kind raise_inspect 'Error token %p in line %d' % [[match, kind], line], tokens, states end raise_inspect 'Empty token', tokens, states unless match tokens << [match, kind] end tokens end
# File lib/coderay/scanners/php.rb, line 14 def setup @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true end
