OSDN Git Service

add Redmine trunk rev 3089
[redminele/redminele.git] / redmine / vendor / plugins / coderay-0.7.6.227 / lib / coderay / scanners / php.rb
1 module CodeRay module Scanners
2         
3         class PHP < Scanner
4
5                 register_for :php
6                 
7                 RESERVED_WORDS = [
8           'and', 'or', 'xor', '__FILE__', 'exception', '__LINE__', 'array', 'as', 'break', 'case',
9           'class', 'const', 'continue', 'declare', 'default',
10           'die', 'do', 'echo', 'else', 'elseif',
11           'empty', 'enddeclare', 'endfor', 'endforeach', 'endif',
12           'endswitch', 'endwhile', 'eval', 'exit', 'extends',
13           'for', 'foreach', 'function', 'global', 'if',
14           'include', 'include_once', 'isset', 'list', 'new',
15           'print', 'require', 'require_once', 'return', 'static',
16           'switch', 'unset', 'use', 'var', 'while',
17           '__FUNCTION__', '__CLASS__', '__METHOD__', 'final', 'php_user_filter',
18           'interface', 'implements', 'extends', 'public', 'private',
19           'protected', 'abstract', 'clone', 'try', 'catch',
20           'throw', 'cfunction', 'old_function' 
21                 ]
22
23                 PREDEFINED_CONSTANTS = [
24                         'null', '$this', 'true', 'false'
25                 ]
26
27                 IDENT_KIND = WordList.new(:ident).
28                         add(RESERVED_WORDS, :reserved).
29                         add(PREDEFINED_CONSTANTS, :pre_constant)
30
31                 ESCAPE = / [\$\wrbfnrtv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
32                 UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
33
34                 def scan_tokens tokens, options
35
36                         state = :waiting_php
37                         string_type = nil
38                         regexp_allowed = true
39
40                         until eos?
41
42                                 kind = :error
43                                 match = nil
44
45                                 if state == :initial
46                                         
47                                         if scan(/ \s+ | \\\n /x)
48                                                 kind = :space
49                                                 
50                                     elsif scan(/\?>/)
51                                     kind = :char
52                                     state = :waiting_php
53                                                 
54                                         elsif scan(%r{ (//|\#) [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) }mx)
55                                                 kind = :comment
56                                                 regexp_allowed = false
57
58                                         elsif match = scan(/ \# \s* if \s* 0 /x)
59                                                 match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
60                                                 kind = :comment
61                                                 regexp_allowed = false
62
63                                   elsif regexp_allowed and scan(/\//)
64                                     tokens << [:open, :regexp]
65                                     state = :regex
66                                                 kind = :delimiter
67                                                 
68                                         elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%] | \.(?!\d) /x)
69                                                 kind = :operator
70                                                 regexp_allowed=true
71                                                 
72                                         elsif match = scan(/ [$@A-Za-z_][A-Za-z_0-9]* /x)
73                                                 kind = IDENT_KIND[match]
74                                                 regexp_allowed=false
75                                                 
76                                         elsif match = scan(/["']/)
77                                                 tokens << [:open, :string]
78                         string_type = matched
79                                                 state = :string
80                                                 kind = :delimiter
81                                 
82                                         elsif scan(/0[xX][0-9A-Fa-f]+/)
83                                                 kind = :hex
84                                                 regexp_allowed=false
85                                                 
86                                         elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)
87                                                 kind = :oct
88                                                 regexp_allowed=false
89                                                 
90                                         elsif scan(/(?:\d+)(?![.eEfF])/)
91                                                 kind = :integer
92                                                 regexp_allowed=false
93                                                 
94                                         elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
95                                                 kind = :float
96                                                 regexp_allowed=false
97
98                                         else
99                                                 getch
100                                         end
101                                         
102                                 elsif state == :regex
103                                         if scan(/[^\\\/]+/)
104                                                 kind = :content
105                                   elsif scan(/\\\/|\\/)
106                                                 kind = :content
107                                   elsif scan(/\//)
108                                           tokens << [matched, :delimiter]
109                                     tokens << [:close, :regexp]
110                                     state = :initial
111                                     next
112                                   else
113                                     getch
114                                     kind = :content
115                                         end
116                                   
117                                 elsif state == :string
118                                         if scan(/[^\\"']+/)
119                                                 kind = :content
120                                         elsif scan(/["']/)
121                                                 if string_type==matched
122                                                   tokens << [matched, :delimiter]
123                                                   tokens << [:close, :string]
124                                                   state = :initial
125                                                   string_type=nil
126                                                   next
127                                                 else
128                                                   kind = :content
129                                                 end
130                                         elsif scan(/ \\ (?: \S ) /mox)
131                                                 kind = :char
132                                         elsif scan(/ \\ | $ /x)
133                                                 kind = :error
134                                                 state = :initial
135                                         else
136                                                 raise "else case \" reached; %p not handled." % peek(1), tokens
137                                         end             
138                                                 
139                                 elsif state == :waiting_php
140                   if scan(/<\?php/m)
141                                     kind = :char
142                                     state = :initial
143                                   elsif scan(/[^<]+/)
144                                     kind = :comment
145                   else
146                     kind = :comment
147                     getch
148                                   end
149                                 else
150                                         raise 'else-case reached', tokens
151                                         
152                                 end
153                                 
154                                 match ||= matched
155         
156                                 tokens << [match, kind]
157                                 
158                         end
159                   tokens
160                         
161                 end
162
163         end
164
165 end end