comparison vendor/gems/coderay-1.0.0/lib/coderay/scanners/java_script.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 # Scanner for JavaScript.
5 #
6 # Aliases: +ecmascript+, +ecma_script+, +javascript+
7 class JavaScript < Scanner
8
9 register_for :java_script
10 file_extension 'js'
11
12 # The actual JavaScript keywords.
13 KEYWORDS = %w[
14 break case catch continue default delete do else
15 finally for function if in instanceof new
16 return switch throw try typeof var void while with
17 ] # :nodoc:
18 PREDEFINED_CONSTANTS = %w[
19 false null true undefined NaN Infinity
20 ] # :nodoc:
21
22 MAGIC_VARIABLES = %w[ this arguments ] # :nodoc: arguments was introduced in JavaScript 1.4
23
24 KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
25 case delete in instanceof new return throw typeof with
26 ] # :nodoc:
27
28 # Reserved for future use.
29 RESERVED_WORDS = %w[
30 abstract boolean byte char class debugger double enum export extends
31 final float goto implements import int interface long native package
32 private protected public short static super synchronized throws transient
33 volatile
34 ] # :nodoc:
35
36 IDENT_KIND = WordList.new(:ident).
37 add(RESERVED_WORDS, :reserved).
38 add(PREDEFINED_CONSTANTS, :predefined_constant).
39 add(MAGIC_VARIABLES, :local_variable).
40 add(KEYWORDS, :keyword) # :nodoc:
41
42 ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc:
43 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc:
44 REGEXP_ESCAPE = / [bBdDsSwW] /x # :nodoc:
45 STRING_CONTENT_PATTERN = {
46 "'" => /[^\\']+/,
47 '"' => /[^\\"]+/,
48 '/' => /[^\\\/]+/,
49 } # :nodoc:
50 KEY_CHECK_PATTERN = {
51 "'" => / (?> [^\\']* (?: \\. [^\\']* )* ) ' \s* : /mx,
52 '"' => / (?> [^\\"]* (?: \\. [^\\"]* )* ) " \s* : /mx,
53 } # :nodoc:
54
55 protected
56
57 def scan_tokens encoder, options
58
59 state = :initial
60 string_delimiter = nil
61 value_expected = true
62 key_expected = false
63 function_expected = false
64
65 until eos?
66
67 case state
68
69 when :initial
70
71 if match = scan(/ \s+ | \\\n /x)
72 value_expected = true if !value_expected && match.index(?\n)
73 encoder.text_token match, :space
74
75 elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
76 value_expected = true
77 encoder.text_token match, :comment
78
79 elsif check(/\.?\d/)
80 key_expected = value_expected = false
81 if match = scan(/0[xX][0-9A-Fa-f]+/)
82 encoder.text_token match, :hex
83 elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/)
84 encoder.text_token match, :octal
85 elsif match = scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
86 encoder.text_token match, :float
87 elsif match = scan(/\d+/)
88 encoder.text_token match, :integer
89 end
90
91 elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim)
92 # TODO: scan over nested tags
93 xml_scanner.tokenize match, :tokens => encoder
94 value_expected = false
95 next
96
97 elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x)
98 value_expected = true
99 last_operator = match[-1]
100 key_expected = (last_operator == ?{) || (last_operator == ?,)
101 function_expected = false
102 encoder.text_token match, :operator
103
104 elsif match = scan(/ [)\]}]+ /x)
105 function_expected = key_expected = value_expected = false
106 encoder.text_token match, :operator
107
108 elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x)
109 kind = IDENT_KIND[match]
110 value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match]
111 # TODO: labels
112 if kind == :ident
113 if match.index(?$) # $ allowed inside an identifier
114 kind = :predefined
115 elsif function_expected
116 kind = :function
117 elsif check(/\s*[=:]\s*function\b/)
118 kind = :function
119 elsif key_expected && check(/\s*:/)
120 kind = :key
121 end
122 end
123 function_expected = (kind == :keyword) && (match == 'function')
124 key_expected = false
125 encoder.text_token match, kind
126
127 elsif match = scan(/["']/)
128 if key_expected && check(KEY_CHECK_PATTERN[match])
129 state = :key
130 else
131 state = :string
132 end
133 encoder.begin_group state
134 string_delimiter = match
135 encoder.text_token match, :delimiter
136
137 elsif value_expected && (match = scan(/\//))
138 encoder.begin_group :regexp
139 state = :regexp
140 string_delimiter = '/'
141 encoder.text_token match, :delimiter
142
143 elsif match = scan(/ \/ /x)
144 value_expected = true
145 key_expected = false
146 encoder.text_token match, :operator
147
148 else
149 encoder.text_token getch, :error
150
151 end
152
153 when :string, :regexp, :key
154 if match = scan(STRING_CONTENT_PATTERN[string_delimiter])
155 encoder.text_token match, :content
156 elsif match = scan(/["'\/]/)
157 encoder.text_token match, :delimiter
158 if state == :regexp
159 modifiers = scan(/[gim]+/)
160 encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty?
161 end
162 encoder.end_group state
163 string_delimiter = nil
164 key_expected = value_expected = false
165 state = :initial
166 elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox))
167 if string_delimiter == "'" && !(match == "\\\\" || match == "\\'")
168 encoder.text_token match, :content
169 else
170 encoder.text_token match, :char
171 end
172 elsif state == :regexp && match = scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
173 encoder.text_token match, :char
174 elsif match = scan(/\\./m)
175 encoder.text_token match, :content
176 elsif match = scan(/ \\ | $ /x)
177 encoder.end_group state
178 encoder.text_token match, :error
179 key_expected = value_expected = false
180 state = :initial
181 else
182 raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
183 end
184
185 else
186 raise_inspect 'Unknown state', encoder
187
188 end
189
190 end
191
192 if [:string, :regexp].include? state
193 encoder.end_group state
194 end
195
196 encoder
197 end
198
199 protected
200
201 def reset_instance
202 super
203 @xml_scanner.reset if defined? @xml_scanner
204 end
205
206 def xml_scanner
207 @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false
208 end
209
210 end
211
212 end
213 end