Skip to content

Commit a4f82e6

Browse files
committed
cloned coffee_script.rb from java_script.rb
1 parent 27e8836 commit a4f82e6

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed

lib/coderay/scanners/coffee_script.rb

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
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

0 commit comments

Comments
 (0)