coderay 0.8.357 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/README +4 -3
- data/lib/coderay.rb +2 -1
- data/lib/coderay/encoder.rb +41 -15
- data/lib/coderay/encoders/_map.rb +3 -1
- data/lib/coderay/encoders/comment_filter.rb +43 -0
- data/lib/coderay/encoders/div.rb +2 -3
- data/lib/coderay/encoders/filter.rb +75 -0
- data/lib/coderay/encoders/html.rb +20 -3
- data/lib/coderay/encoders/html/css.rb +1 -1
- data/lib/coderay/encoders/html/numerization.rb +11 -2
- data/lib/coderay/encoders/html/output.rb +10 -1
- data/lib/coderay/encoders/json.rb +69 -0
- data/lib/coderay/encoders/lines_of_code.rb +90 -0
- data/lib/coderay/encoders/page.rb +1 -2
- data/lib/coderay/encoders/span.rb +2 -3
- data/lib/coderay/encoders/term.rb +137 -0
- data/lib/coderay/encoders/text.rb +4 -4
- data/lib/coderay/encoders/token_class_filter.rb +84 -0
- data/lib/coderay/encoders/xml.rb +1 -0
- data/lib/coderay/for_redcloth.rb +9 -4
- data/lib/coderay/helpers/file_type.rb +54 -15
- data/lib/coderay/helpers/plugin.rb +21 -3
- data/lib/coderay/helpers/word_list.rb +19 -4
- data/lib/coderay/scanner.rb +33 -2
- data/lib/coderay/scanners/_map.rb +10 -4
- data/lib/coderay/scanners/c.rb +61 -23
- data/lib/coderay/scanners/cpp.rb +228 -0
- data/lib/coderay/scanners/css.rb +9 -1
- data/lib/coderay/scanners/debug.rb +1 -0
- data/lib/coderay/scanners/delphi.rb +2 -2
- data/lib/coderay/scanners/diff.rb +1 -0
- data/lib/coderay/scanners/groovy.rb +263 -0
- data/lib/coderay/scanners/html.rb +9 -2
- data/lib/coderay/scanners/java.rb +18 -14
- data/lib/coderay/scanners/java_script.rb +42 -13
- data/lib/coderay/scanners/json.rb +7 -1
- data/lib/coderay/scanners/nitro_xhtml.rb +4 -0
- data/lib/coderay/scanners/php.rb +526 -0
- data/lib/coderay/scanners/plaintext.rb +4 -1
- data/lib/coderay/scanners/python.rb +285 -0
- data/lib/coderay/scanners/rhtml.rb +3 -0
- data/lib/coderay/scanners/ruby.rb +29 -11
- data/lib/coderay/scanners/ruby/patterns.rb +26 -20
- data/lib/coderay/scanners/scheme.rb +3 -0
- data/lib/coderay/scanners/sql.rb +162 -0
- data/lib/coderay/scanners/xml.rb +1 -1
- data/lib/coderay/scanners/yaml.rb +4 -1
- data/lib/coderay/styles/cycnus.rb +11 -7
- data/lib/coderay/token_classes.rb +4 -1
- data/lib/coderay/tokens.rb +50 -46
- metadata +14 -4
- data/lib/coderay/encoders/tokens.rb +0 -44
data/lib/coderay/scanners/css.rb
CHANGED
@@ -5,6 +5,14 @@ module Scanners
|
|
5
5
|
|
6
6
|
register_for :css
|
7
7
|
|
8
|
+
KINDS_NOT_LOC = [
|
9
|
+
:comment,
|
10
|
+
:class, :pseudo_class, :type,
|
11
|
+
:constant, :directive,
|
12
|
+
:key, :value, :operator, :color, :float,
|
13
|
+
:error, :important,
|
14
|
+
]
|
15
|
+
|
8
16
|
module RE
|
9
17
|
NonASCII = /[\x80-\xFF]/
|
10
18
|
Hex = /[0-9a-fA-F]/
|
@@ -58,7 +66,7 @@ module Scanners
|
|
58
66
|
elsif case states.last
|
59
67
|
when :initial, :media
|
60
68
|
if scan(/(?>#{RE::Ident})(?!\()|\*/ox)
|
61
|
-
kind = :
|
69
|
+
kind = :type
|
62
70
|
elsif scan RE::Class
|
63
71
|
kind = :class
|
64
72
|
elsif scan RE::Id
|
@@ -30,11 +30,11 @@ module Scanners
|
|
30
30
|
'virtual', 'write', 'writeonly'
|
31
31
|
]
|
32
32
|
|
33
|
-
IDENT_KIND = CaseIgnoringWordList.new(:ident
|
33
|
+
IDENT_KIND = CaseIgnoringWordList.new(:ident).
|
34
34
|
add(RESERVED_WORDS, :reserved).
|
35
35
|
add(DIRECTIVES, :directive)
|
36
36
|
|
37
|
-
NAME_FOLLOWS = CaseIgnoringWordList.new(false
|
37
|
+
NAME_FOLLOWS = CaseIgnoringWordList.new(false).
|
38
38
|
add(%w(procedure function .))
|
39
39
|
|
40
40
|
private
|
@@ -0,0 +1,263 @@
|
|
1
|
+
module CodeRay
|
2
|
+
module Scanners
|
3
|
+
|
4
|
+
load :java
|
5
|
+
|
6
|
+
class Groovy < Java
|
7
|
+
|
8
|
+
include Streamable
|
9
|
+
register_for :groovy
|
10
|
+
|
11
|
+
# TODO: Check this!
|
12
|
+
GROOVY_KEYWORDS = %w[
|
13
|
+
as assert def in
|
14
|
+
]
|
15
|
+
KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
|
16
|
+
case instanceof new return throw typeof while as assert in
|
17
|
+
]
|
18
|
+
GROOVY_MAGIC_VARIABLES = %w[ it ]
|
19
|
+
|
20
|
+
IDENT_KIND = Java::IDENT_KIND.dup.
|
21
|
+
add(GROOVY_KEYWORDS, :keyword).
|
22
|
+
add(GROOVY_MAGIC_VARIABLES, :local_variable)
|
23
|
+
|
24
|
+
ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
|
25
|
+
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # no 4-byte unicode chars? U[a-fA-F0-9]{8}
|
26
|
+
REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x
|
27
|
+
|
28
|
+
# TODO: interpretation inside ', ", /
|
29
|
+
STRING_CONTENT_PATTERN = {
|
30
|
+
"'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/,
|
31
|
+
'"' => /[^\\$"\n]+/,
|
32
|
+
"'''" => /(?>[^\\']+|'(?!''))+/,
|
33
|
+
'"""' => /(?>[^\\$"]+|"(?!""))+/,
|
34
|
+
'/' => /[^\\$\/\n]+/,
|
35
|
+
}
|
36
|
+
|
37
|
+
def scan_tokens tokens, options
|
38
|
+
|
39
|
+
state = :initial
|
40
|
+
inline_block_stack = []
|
41
|
+
inline_block_paren_depth = nil
|
42
|
+
string_delimiter = nil
|
43
|
+
import_clause = class_name_follows = last_token = after_def = false
|
44
|
+
value_expected = true
|
45
|
+
|
46
|
+
until eos?
|
47
|
+
|
48
|
+
kind = nil
|
49
|
+
match = nil
|
50
|
+
|
51
|
+
case state
|
52
|
+
|
53
|
+
when :initial
|
54
|
+
|
55
|
+
if match = scan(/ \s+ | \\\n /x)
|
56
|
+
tokens << [match, :space]
|
57
|
+
if match.index ?\n
|
58
|
+
import_clause = after_def = false
|
59
|
+
value_expected = true unless value_expected
|
60
|
+
end
|
61
|
+
next
|
62
|
+
|
63
|
+
elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
|
64
|
+
value_expected = true
|
65
|
+
after_def = false
|
66
|
+
kind = :comment
|
67
|
+
|
68
|
+
elsif bol? && scan(/ \#!.* /x)
|
69
|
+
kind = :doctype
|
70
|
+
|
71
|
+
elsif import_clause && scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox)
|
72
|
+
after_def = value_expected = false
|
73
|
+
kind = :include
|
74
|
+
|
75
|
+
elsif match = scan(/ #{IDENT} | \[\] /ox)
|
76
|
+
kind = IDENT_KIND[match]
|
77
|
+
value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match]
|
78
|
+
if last_token == '.'
|
79
|
+
kind = :ident
|
80
|
+
elsif class_name_follows
|
81
|
+
kind = :class
|
82
|
+
class_name_follows = false
|
83
|
+
elsif after_def && check(/\s*[({]/)
|
84
|
+
kind = :method
|
85
|
+
after_def = false
|
86
|
+
elsif kind == :ident && last_token != '?' && check(/:/)
|
87
|
+
kind = :key
|
88
|
+
else
|
89
|
+
class_name_follows = true if match == 'class' || (import_clause && match == 'as')
|
90
|
+
import_clause = match == 'import'
|
91
|
+
after_def = true if match == 'def'
|
92
|
+
end
|
93
|
+
|
94
|
+
elsif scan(/;/)
|
95
|
+
import_clause = after_def = false
|
96
|
+
value_expected = true
|
97
|
+
kind = :operator
|
98
|
+
|
99
|
+
elsif scan(/\{/)
|
100
|
+
class_name_follows = after_def = false
|
101
|
+
value_expected = true
|
102
|
+
kind = :operator
|
103
|
+
if !inline_block_stack.empty?
|
104
|
+
inline_block_paren_depth += 1
|
105
|
+
end
|
106
|
+
|
107
|
+
# TODO: ~'...', ~"..." and ~/.../ style regexps
|
108
|
+
elsif match = scan(/ \.\.<? | \*?\.(?!\d)@? | \.& | \?:? | [,?:(\[] | -[->] | \+\+ |
|
109
|
+
&& | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<<?=? | >>>?=? /x)
|
110
|
+
value_expected = true
|
111
|
+
value_expected = :regexp if match == '~'
|
112
|
+
after_def = false
|
113
|
+
kind = :operator
|
114
|
+
|
115
|
+
elsif match = scan(/ [)\]}] /x)
|
116
|
+
value_expected = after_def = false
|
117
|
+
if !inline_block_stack.empty? && match == '}'
|
118
|
+
inline_block_paren_depth -= 1
|
119
|
+
if inline_block_paren_depth == 0 # closing brace of inline block reached
|
120
|
+
tokens << [match, :inline_delimiter]
|
121
|
+
tokens << [:close, :inline]
|
122
|
+
state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop
|
123
|
+
next
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
elsif check(/[\d.]/)
|
128
|
+
after_def = value_expected = false
|
129
|
+
if scan(/0[xX][0-9A-Fa-f]+/)
|
130
|
+
kind = :hex
|
131
|
+
elsif scan(/(?>0[0-7]+)(?![89.eEfF])/)
|
132
|
+
kind = :oct
|
133
|
+
elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/)
|
134
|
+
kind = :float
|
135
|
+
elsif scan(/\d+[lLgG]?/)
|
136
|
+
kind = :integer
|
137
|
+
end
|
138
|
+
|
139
|
+
elsif match = scan(/'''|"""/)
|
140
|
+
after_def = value_expected = false
|
141
|
+
state = :multiline_string
|
142
|
+
tokens << [:open, :string]
|
143
|
+
string_delimiter = match
|
144
|
+
kind = :delimiter
|
145
|
+
|
146
|
+
# TODO: record.'name'
|
147
|
+
elsif match = scan(/["']/)
|
148
|
+
after_def = value_expected = false
|
149
|
+
state = match == '/' ? :regexp : :string
|
150
|
+
tokens << [:open, state]
|
151
|
+
string_delimiter = match
|
152
|
+
kind = :delimiter
|
153
|
+
|
154
|
+
elsif value_expected && (match = scan(/\//))
|
155
|
+
after_def = value_expected = false
|
156
|
+
tokens << [:open, :regexp]
|
157
|
+
state = :regexp
|
158
|
+
string_delimiter = '/'
|
159
|
+
kind = :delimiter
|
160
|
+
|
161
|
+
elsif scan(/ @ #{IDENT} /ox)
|
162
|
+
after_def = value_expected = false
|
163
|
+
kind = :annotation
|
164
|
+
|
165
|
+
elsif scan(/\//)
|
166
|
+
after_def = false
|
167
|
+
value_expected = true
|
168
|
+
kind = :operator
|
169
|
+
|
170
|
+
else
|
171
|
+
getch
|
172
|
+
kind = :error
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
when :string, :regexp, :multiline_string
|
177
|
+
if scan(STRING_CONTENT_PATTERN[string_delimiter])
|
178
|
+
kind = :content
|
179
|
+
|
180
|
+
elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/)
|
181
|
+
tokens << [match, :delimiter]
|
182
|
+
if state == :regexp
|
183
|
+
# TODO: regexp modifiers? s, m, x, i?
|
184
|
+
modifiers = scan(/[ix]+/)
|
185
|
+
tokens << [modifiers, :modifier] if modifiers && !modifiers.empty?
|
186
|
+
end
|
187
|
+
state = :string if state == :multiline_string
|
188
|
+
tokens << [:close, state]
|
189
|
+
string_delimiter = nil
|
190
|
+
after_def = value_expected = false
|
191
|
+
state = :initial
|
192
|
+
next
|
193
|
+
|
194
|
+
elsif (state == :string || state == :multiline_string) &&
|
195
|
+
(match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox))
|
196
|
+
if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'")
|
197
|
+
kind = :content
|
198
|
+
else
|
199
|
+
kind = :char
|
200
|
+
end
|
201
|
+
elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
|
202
|
+
kind = :char
|
203
|
+
|
204
|
+
elsif match = scan(/ \$ #{IDENT} /mox)
|
205
|
+
tokens << [:open, :inline]
|
206
|
+
tokens << ['$', :inline_delimiter]
|
207
|
+
match = match[1..-1]
|
208
|
+
tokens << [match, IDENT_KIND[match]]
|
209
|
+
tokens << [:close, :inline]
|
210
|
+
next
|
211
|
+
elsif match = scan(/ \$ \{ /x)
|
212
|
+
tokens << [:open, :inline]
|
213
|
+
tokens << ['${', :inline_delimiter]
|
214
|
+
inline_block_stack << [state, string_delimiter, inline_block_paren_depth]
|
215
|
+
inline_block_paren_depth = 1
|
216
|
+
state = :initial
|
217
|
+
next
|
218
|
+
|
219
|
+
elsif scan(/ \$ /mx)
|
220
|
+
kind = :content
|
221
|
+
|
222
|
+
elsif scan(/ \\. /mx)
|
223
|
+
kind = :content
|
224
|
+
|
225
|
+
elsif scan(/ \\ | \n /x)
|
226
|
+
tokens << [:close, state]
|
227
|
+
kind = :error
|
228
|
+
after_def = value_expected = false
|
229
|
+
state = :initial
|
230
|
+
|
231
|
+
else
|
232
|
+
raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
|
233
|
+
end
|
234
|
+
|
235
|
+
else
|
236
|
+
raise_inspect 'Unknown state', tokens
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
match ||= matched
|
241
|
+
if $DEBUG and not kind
|
242
|
+
raise_inspect 'Error token %p in line %d' %
|
243
|
+
[[match, kind], line], tokens
|
244
|
+
end
|
245
|
+
raise_inspect 'Empty token', tokens unless match
|
246
|
+
|
247
|
+
last_token = match unless [:space, :comment, :doctype].include? kind
|
248
|
+
|
249
|
+
tokens << [match, kind]
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
if [:multiline_string, :string, :regexp].include? state
|
254
|
+
tokens << [:close, state]
|
255
|
+
end
|
256
|
+
|
257
|
+
tokens
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
end
|
@@ -6,6 +6,13 @@ module Scanners
|
|
6
6
|
|
7
7
|
include Streamable
|
8
8
|
register_for :html
|
9
|
+
|
10
|
+
KINDS_NOT_LOC = [
|
11
|
+
:comment, :doctype, :preprocessor,
|
12
|
+
:tag, :attribute_name, :operator,
|
13
|
+
:attribute_value, :delimiter, :content,
|
14
|
+
:plain, :entity, :error
|
15
|
+
]
|
9
16
|
|
10
17
|
ATTR_NAME = /[\w.:-]+/
|
11
18
|
ATTR_VALUE_UNQUOTED = ATTR_NAME
|
@@ -68,9 +75,9 @@ module Scanners
|
|
68
75
|
kind = :preprocessor
|
69
76
|
elsif scan(/<\?.*?\?>|<%.*?%>/m)
|
70
77
|
kind = :comment
|
71
|
-
elsif scan(/<\/[-\
|
78
|
+
elsif scan(/<\/[-\w.:]*>/m)
|
72
79
|
kind = :tag
|
73
|
-
elsif match = scan(/<[-\
|
80
|
+
elsif match = scan(/<[-\w.:]+>?/m)
|
74
81
|
kind = :tag
|
75
82
|
state = :attribute unless match[-1] == ?>
|
76
83
|
elsif scan(/[^<>&]+/)
|
@@ -7,30 +7,33 @@ module Scanners
|
|
7
7
|
register_for :java
|
8
8
|
helper :builtin_types
|
9
9
|
|
10
|
-
#
|
10
|
+
# http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
|
11
11
|
KEYWORDS = %w[
|
12
|
-
break case catch continue default do else
|
13
|
-
|
14
|
-
return switch throw
|
15
|
-
debugger export
|
12
|
+
assert break case catch continue default do else
|
13
|
+
finally for if instanceof import new package
|
14
|
+
return switch throw try typeof while
|
15
|
+
debugger export
|
16
16
|
]
|
17
|
-
|
17
|
+
RESERVED = %w[ const goto ]
|
18
|
+
CONSTANTS = %w[ false null true ]
|
18
19
|
MAGIC_VARIABLES = %w[ this super ]
|
19
20
|
TYPES = %w[
|
20
|
-
boolean byte char class
|
21
|
-
|
21
|
+
boolean byte char class double enum float int interface long
|
22
|
+
short void
|
23
|
+
] << '[]' # because int[] should be highlighted as a type
|
22
24
|
DIRECTIVES = %w[
|
23
25
|
abstract extends final implements native private protected public
|
24
|
-
static strictfp synchronized
|
26
|
+
static strictfp synchronized throws transient volatile
|
25
27
|
]
|
26
28
|
|
27
|
-
# Reserved for future use.
|
28
|
-
|
29
29
|
IDENT_KIND = WordList.new(:ident).
|
30
30
|
add(KEYWORDS, :keyword).
|
31
|
+
add(RESERVED, :reserved).
|
32
|
+
add(CONSTANTS, :pre_constant).
|
31
33
|
add(MAGIC_VARIABLES, :local_variable).
|
32
34
|
add(TYPES, :type).
|
33
35
|
add(BuiltinTypes::List, :pre_type).
|
36
|
+
add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception).
|
34
37
|
add(DIRECTIVES, :directive)
|
35
38
|
|
36
39
|
ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
|
@@ -61,8 +64,9 @@ module Scanners
|
|
61
64
|
tokens << [match, :space]
|
62
65
|
next
|
63
66
|
|
64
|
-
elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
|
65
|
-
|
67
|
+
elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
|
68
|
+
tokens << [match, :comment]
|
69
|
+
next
|
66
70
|
|
67
71
|
elsif import_clause && scan(/ #{IDENT} (?: \. #{IDENT} )* /ox)
|
68
72
|
kind = :include
|
@@ -79,7 +83,7 @@ module Scanners
|
|
79
83
|
class_name_follows = true if match == 'class' || match == 'interface'
|
80
84
|
end
|
81
85
|
|
82
|
-
elsif scan(/ \.(?!\d) | [,?:(\[
|
86
|
+
elsif scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<<?=? | >>>?=? /x)
|
83
87
|
kind = :operator
|
84
88
|
|
85
89
|
elsif scan(/;/)
|
@@ -11,14 +11,17 @@ module Scanners
|
|
11
11
|
# The actual JavaScript keywords.
|
12
12
|
KEYWORDS = %w[
|
13
13
|
break case catch continue default delete do else
|
14
|
-
|
15
|
-
return switch throw
|
14
|
+
finally for function if in instanceof new
|
15
|
+
return switch throw try typeof var void while with
|
16
|
+
]
|
17
|
+
PREDEFINED_CONSTANTS = %w[
|
18
|
+
false null true undefined
|
16
19
|
]
|
17
20
|
|
18
21
|
MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4
|
19
22
|
|
20
23
|
KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[
|
21
|
-
case delete in instanceof new return throw typeof
|
24
|
+
case delete in instanceof new return throw typeof with
|
22
25
|
]
|
23
26
|
|
24
27
|
# Reserved for future use.
|
@@ -31,6 +34,7 @@ module Scanners
|
|
31
34
|
|
32
35
|
IDENT_KIND = WordList.new(:ident).
|
33
36
|
add(RESERVED_WORDS, :reserved).
|
37
|
+
add(PREDEFINED_CONSTANTS, :pre_constant).
|
34
38
|
add(MAGIC_VARIABLES, :local_variable).
|
35
39
|
add(KEYWORDS, :keyword)
|
36
40
|
|
@@ -53,6 +57,7 @@ module Scanners
|
|
53
57
|
string_delimiter = nil
|
54
58
|
value_expected = true
|
55
59
|
key_expected = false
|
60
|
+
function_expected = false
|
56
61
|
|
57
62
|
until eos?
|
58
63
|
|
@@ -72,7 +77,7 @@ module Scanners
|
|
72
77
|
value_expected = true
|
73
78
|
kind = :comment
|
74
79
|
|
75
|
-
elsif check(
|
80
|
+
elsif check(/\.?\d/)
|
76
81
|
key_expected = value_expected = false
|
77
82
|
if scan(/0[xX][0-9A-Fa-f]+/)
|
78
83
|
kind = :hex
|
@@ -83,29 +88,42 @@ module Scanners
|
|
83
88
|
elsif scan(/\d+/)
|
84
89
|
kind = :integer
|
85
90
|
end
|
91
|
+
|
92
|
+
elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim)
|
93
|
+
# FIXME: scan over nested tags
|
94
|
+
xml_scanner.tokenize match
|
95
|
+
value_expected = false
|
96
|
+
next
|
86
97
|
|
87
98
|
elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x)
|
88
99
|
value_expected = true
|
89
100
|
last_operator = match[-1]
|
90
101
|
key_expected = (last_operator == ?{) || (last_operator == ?,)
|
102
|
+
function_expected = false
|
91
103
|
kind = :operator
|
92
104
|
|
93
105
|
elsif scan(/ [)\]}]+ /x)
|
94
|
-
key_expected = value_expected = false
|
106
|
+
function_expected = key_expected = value_expected = false
|
95
107
|
kind = :operator
|
96
108
|
|
97
109
|
elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x)
|
98
110
|
kind = IDENT_KIND[match]
|
99
111
|
value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match]
|
112
|
+
# TODO: labels
|
100
113
|
if kind == :ident
|
101
|
-
if match.index(?$)
|
114
|
+
if match.index(?$) # $ allowed inside an identifier
|
102
115
|
kind = :predefined
|
116
|
+
elsif function_expected
|
117
|
+
kind = :function
|
118
|
+
elsif check(/\s*[=:]\s*function\b/)
|
119
|
+
kind = :function
|
103
120
|
elsif key_expected && check(/\s*:/)
|
104
121
|
kind = :key
|
105
122
|
end
|
106
123
|
end
|
124
|
+
function_expected = (kind == :keyword) && (match == 'function')
|
107
125
|
key_expected = false
|
108
|
-
|
126
|
+
|
109
127
|
elsif match = scan(/["']/)
|
110
128
|
if key_expected && check(KEY_CHECK_PATTERN[match])
|
111
129
|
state = :key
|
@@ -158,25 +176,25 @@ module Scanners
|
|
158
176
|
elsif scan(/\\./m)
|
159
177
|
kind = :content
|
160
178
|
elsif scan(/ \\ | $ /x)
|
161
|
-
tokens << [:close,
|
179
|
+
tokens << [:close, state]
|
162
180
|
kind = :error
|
163
181
|
key_expected = value_expected = false
|
164
182
|
state = :initial
|
165
183
|
else
|
166
|
-
raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
|
184
|
+
raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
|
167
185
|
end
|
168
186
|
|
169
187
|
else
|
170
|
-
raise_inspect 'Unknown state', tokens
|
188
|
+
raise_inspect 'Unknown state', tokens
|
171
189
|
|
172
190
|
end
|
173
191
|
|
174
192
|
match ||= matched
|
175
193
|
if $DEBUG and not kind
|
176
194
|
raise_inspect 'Error token %p in line %d' %
|
177
|
-
[[match, kind], line], tokens
|
195
|
+
[[match, kind], line], tokens
|
178
196
|
end
|
179
|
-
raise_inspect 'Empty token', tokens
|
197
|
+
raise_inspect 'Empty token', tokens unless match
|
180
198
|
|
181
199
|
tokens << [match, kind]
|
182
200
|
|
@@ -189,7 +207,18 @@ module Scanners
|
|
189
207
|
tokens
|
190
208
|
end
|
191
209
|
|
192
|
-
|
210
|
+
protected
|
193
211
|
|
212
|
+
def reset_instance
|
213
|
+
super
|
214
|
+
@xml_scanner.reset if defined? @xml_scanner
|
215
|
+
end
|
216
|
+
|
217
|
+
def xml_scanner
|
218
|
+
@xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => true
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
194
223
|
end
|
195
224
|
end
|