coderay 0.7.4.215 → 0.8.260

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.
Files changed (47) hide show
  1. data/LICENSE +421 -257
  2. data/README +24 -13
  3. data/bin/coderay +9 -4
  4. data/lib/coderay.rb +19 -17
  5. data/lib/coderay/duo.rb +67 -9
  6. data/lib/coderay/encoder.rb +18 -9
  7. data/lib/coderay/encoders/_map.rb +2 -1
  8. data/lib/coderay/encoders/debug.rb +14 -11
  9. data/lib/coderay/encoders/html.rb +44 -17
  10. data/lib/coderay/encoders/html/css.rb +13 -8
  11. data/lib/coderay/encoders/html/numerization.rb +8 -6
  12. data/lib/coderay/encoders/html/output.rb +3 -1
  13. data/lib/coderay/encoders/statistic.rb +2 -6
  14. data/lib/coderay/encoders/text.rb +2 -3
  15. data/lib/coderay/encoders/tokens.rb +3 -3
  16. data/lib/coderay/encoders/xml.rb +1 -2
  17. data/lib/coderay/for_redcloth.rb +72 -0
  18. data/lib/coderay/helpers/file_type.rb +38 -9
  19. data/lib/coderay/helpers/gzip_simple.rb +1 -0
  20. data/lib/coderay/helpers/plugin.rb +15 -8
  21. data/lib/coderay/helpers/word_list.rb +4 -0
  22. data/lib/coderay/scanner.rb +30 -13
  23. data/lib/coderay/scanners/_map.rb +1 -1
  24. data/lib/coderay/scanners/c.rb +3 -1
  25. data/lib/coderay/scanners/css.rb +181 -0
  26. data/lib/coderay/scanners/debug.rb +1 -0
  27. data/lib/coderay/scanners/delphi.rb +1 -0
  28. data/lib/coderay/scanners/diff.rb +104 -0
  29. data/lib/coderay/scanners/java.rb +179 -0
  30. data/lib/coderay/scanners/java/builtin_types.rb +419 -0
  31. data/lib/coderay/scanners/java_script.rb +187 -0
  32. data/lib/coderay/scanners/json.rb +106 -0
  33. data/lib/coderay/scanners/nitro_xhtml.rb +5 -4
  34. data/lib/coderay/scanners/plaintext.rb +2 -0
  35. data/lib/coderay/scanners/rhtml.rb +2 -2
  36. data/lib/coderay/scanners/ruby.rb +64 -50
  37. data/lib/coderay/scanners/ruby/patterns.rb +15 -19
  38. data/lib/coderay/scanners/scheme.rb +142 -0
  39. data/lib/coderay/scanners/sql.Keith.rb +143 -0
  40. data/lib/coderay/scanners/sql.rb +154 -0
  41. data/lib/coderay/scanners/xml.rb +1 -0
  42. data/lib/coderay/styles/cycnus.rb +30 -9
  43. data/lib/coderay/styles/murphy.rb +15 -2
  44. data/lib/coderay/{encoders/html/classes.rb → token_classes.rb} +14 -9
  45. data/lib/coderay/tokens.rb +33 -14
  46. data/lib/term/ansicolor.rb +220 -0
  47. metadata +62 -44
@@ -0,0 +1,106 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ class JSON < Scanner
5
+
6
+ include Streamable
7
+
8
+ register_for :json
9
+
10
+ CONSTANTS = %w( true false null )
11
+ IDENT_KIND = WordList.new(:key).add(CONSTANTS, :reserved)
12
+
13
+ ESCAPE = / [bfnrt\\"\/] /x
14
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x
15
+
16
+ def scan_tokens tokens, options
17
+
18
+ state = :initial
19
+ stack = []
20
+ string_delimiter = nil
21
+ key_expected = false
22
+
23
+ until eos?
24
+
25
+ kind = nil
26
+ match = nil
27
+
28
+ case state
29
+
30
+ when :initial
31
+ if match = scan(/ \s+ | \\\n /x)
32
+ tokens << [match, :space]
33
+ next
34
+ elsif match = scan(/ [:,\[{\]}] /x)
35
+ kind = :operator
36
+ case match
37
+ when '{': stack << :object; key_expected = true
38
+ when '[': stack << :array
39
+ when ':': key_expected = false
40
+ when ',': key_expected = true if stack.last == :object
41
+ when '}', ']': stack.pop # no error recovery, but works for valid JSON
42
+ end
43
+ elsif match = scan(/ true | false | null /x)
44
+ kind = IDENT_KIND[match]
45
+ elsif match = scan(/-?(?:0|[1-9]\d*)/)
46
+ kind = :integer
47
+ if scan(/\.\d+(?:[eE][-+]?\d+)?|[eE][-+]?\d+/)
48
+ match << matched
49
+ kind = :float
50
+ end
51
+ elsif match = scan(/"/)
52
+ state = key_expected ? :key : :string
53
+ tokens << [:open, state]
54
+ kind = :delimiter
55
+ else
56
+ getch
57
+ kind = :error
58
+ end
59
+
60
+ when :string, :key
61
+ if scan(/[^\\"]+/)
62
+ kind = :content
63
+ elsif scan(/"/)
64
+ tokens << ['"', :delimiter]
65
+ tokens << [:close, state]
66
+ state = :initial
67
+ next
68
+ elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
69
+ kind = :char
70
+ elsif scan(/\\./m)
71
+ kind = :content
72
+ elsif scan(/ \\ | $ /x)
73
+ tokens << [:close, :delimiter]
74
+ kind = :error
75
+ state = :initial
76
+ else
77
+ raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
78
+ end
79
+
80
+ else
81
+ raise_inspect 'Unknown state', tokens
82
+
83
+ end
84
+
85
+ match ||= matched
86
+ if $DEBUG and not kind
87
+ raise_inspect 'Error token %p in line %d' %
88
+ [[match, kind], line], tokens
89
+ end
90
+ raise_inspect 'Empty token', tokens unless match
91
+
92
+ tokens << [match, kind]
93
+
94
+ end
95
+
96
+ if [:string, :key].include? state
97
+ tokens << [:close, state]
98
+ end
99
+
100
+ tokens
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end
@@ -11,6 +11,7 @@ module Scanners
11
11
 
12
12
  include Streamable
13
13
  register_for :nitro_xhtml
14
+ file_extension :xhtml
14
15
 
15
16
  NITRO_RUBY_BLOCK = /
16
17
  <\?r
@@ -95,20 +96,20 @@ module Scanners
95
96
  delimiter = CLOSING_PAREN[start_tag[1,1]]
96
97
  end_tag = match[-1,1] == delimiter ? delimiter : ''
97
98
  tokens << [:open, :inline]
98
- tokens << [start_tag, :delimiter]
99
+ tokens << [start_tag, :inline_delimiter]
99
100
  code = match[start_tag.size .. -1 - end_tag.size]
100
101
  @ruby_scanner.tokenize code
101
- tokens << [end_tag, :delimiter] unless end_tag.empty?
102
+ tokens << [end_tag, :inline_delimiter] unless end_tag.empty?
102
103
  tokens << [:close, :inline]
103
104
 
104
105
  elsif match = scan(/#{NITRO_RUBY_BLOCK}/o)
105
106
  start_tag = '<?r'
106
107
  end_tag = match[-2,2] == '?>' ? '?>' : ''
107
108
  tokens << [:open, :inline]
108
- tokens << [start_tag, :delimiter]
109
+ tokens << [start_tag, :inline_delimiter]
109
110
  code = match[start_tag.size .. -(end_tag.size)-1]
110
111
  @ruby_scanner.tokenize code
111
- tokens << [end_tag, :delimiter] unless end_tag.empty?
112
+ tokens << [end_tag, :inline_delimiter] unless end_tag.empty?
112
113
  tokens << [:close, :inline]
113
114
 
114
115
  elsif entity = scan(/#{NITRO_ENTITY}/o)
@@ -4,6 +4,8 @@ module Scanners
4
4
  class Plaintext < Scanner
5
5
 
6
6
  register_for :plaintext, :plain
7
+
8
+ include Streamable
7
9
 
8
10
  def scan_tokens tokens, options
9
11
  text = (scan_until(/\z/) || '')
@@ -51,10 +51,10 @@ module Scanners
51
51
  start_tag = match[/\A<%[-=]?/]
52
52
  end_tag = match[/-?%?>?\z/]
53
53
  tokens << [:open, :inline]
54
- tokens << [start_tag, :delimiter]
54
+ tokens << [start_tag, :inline_delimiter]
55
55
  code = match[start_tag.size .. -1 - end_tag.size]
56
56
  @ruby_scanner.tokenize code
57
- tokens << [end_tag, :delimiter] unless end_tag.empty?
57
+ tokens << [end_tag, :inline_delimiter] unless end_tag.empty?
58
58
  tokens << [:close, :inline]
59
59
 
60
60
  else
@@ -18,6 +18,7 @@ module Scanners
18
18
  include Streamable
19
19
 
20
20
  register_for :ruby
21
+ file_extension 'rb'
21
22
 
22
23
  helper :patterns
23
24
 
@@ -90,15 +91,15 @@ module Scanners
90
91
  end
91
92
 
92
93
  when '#'
93
- case peek(1)[0]
94
- when ?{
94
+ case peek(1)
95
+ when '{'
95
96
  inline_block_stack << [state, depth, heredocs]
96
97
  value_expected = true
97
98
  state = :initial
98
99
  depth = 1
99
100
  tokens << [:open, :inline]
100
101
  tokens << [match + getch, :inline_delimiter]
101
- when ?$, ?@
102
+ when '$', '@'
102
103
  tokens << [match, :escape]
103
104
  last_state = state # scan one token as normal code, then return here
104
105
  state = :initial
@@ -121,36 +122,37 @@ module Scanners
121
122
  # }}}
122
123
  else
123
124
  # {{{
124
- if match = scan(/ [ \t\f]+ | \\? \n | \# .* /x) or
125
- ( bol? and match = scan(/#{patterns::RUBYDOC_OR_DATA}/o) )
126
- case m = match[0]
127
- when ?\s, ?\t, ?\f
128
- match << scan(/\s*/) unless eos? or heredocs
129
- kind = :space
130
- when ?\n, ?\\
131
- kind = :space
132
- if m == ?\n
133
- value_expected = true # FIXME not quite true
134
- state = :initial if state == :undef_comma_expected
135
- end
136
- if heredocs
137
- unscan # heredoc scanning needs \n at start
138
- state = heredocs.shift
139
- tokens << [:open, state.type]
140
- heredocs = nil if heredocs.empty?
141
- next
142
- else
143
- match << scan(/\s*/) unless eos?
144
- end
145
- when ?#, ?=, ?_
146
- kind = :comment
147
- value_expected = true
125
+ if match = scan(/[ \t\f]+/)
126
+ kind = :space
127
+ match << scan(/\s*/) unless eos? || heredocs
128
+ value_expected = true if match.index(?\n) # FIXME not quite true
129
+ tokens << [match, kind]
130
+ next
131
+
132
+ elsif match = scan(/\\?\n/)
133
+ kind = :space
134
+ if match == "\n"
135
+ value_expected = true # FIXME not quite true
136
+ state = :initial if state == :undef_comma_expected
137
+ end
138
+ if heredocs
139
+ unscan # heredoc scanning needs \n at start
140
+ state = heredocs.shift
141
+ tokens << [:open, state.type]
142
+ heredocs = nil if heredocs.empty?
143
+ next
148
144
  else
149
- raise_inspect 'else-case _ reached, because case %p was
150
- not handled' % [matched[0].chr], tokens
145
+ match << scan(/\s*/) unless eos?
151
146
  end
152
147
  tokens << [match, kind]
153
148
  next
149
+
150
+ elsif match = scan(/\#.*/) or
151
+ ( bol? and match = scan(/#{patterns::RUBYDOC_OR_DATA}/o) )
152
+ kind = :comment
153
+ value_expected = true
154
+ tokens << [match, kind]
155
+ next
154
156
 
155
157
  elsif state == :initial
156
158
 
@@ -167,19 +169,19 @@ module Scanners
167
169
  end
168
170
  end
169
171
  ## experimental!
170
- value_expected = :set if
171
- patterns::REGEXP_ALLOWED[match] or check(/#{patterns::VALUE_FOLLOWS}/o)
172
+ value_expected = :set if check(/#{patterns::VALUE_FOLLOWS}/o)
172
173
 
173
174
  elsif last_token_dot and match = scan(/#{patterns::METHOD_NAME_OPERATOR}/o)
174
175
  kind = :ident
175
176
  value_expected = :set if check(/#{patterns::VALUE_FOLLOWS}/o)
176
177
 
177
178
  # OPERATORS #
178
- elsif not last_token_dot and match = scan(/ ==?=? | \.\.?\.? | [\(\)\[\]\{\}] | :: | , /x)
179
+ # TODO: match (), [], {} as one single operator
180
+ elsif not last_token_dot and match = scan(/ \.\.\.? | (?:\.|::)() | [,\(\)\[\]\{\}] | ==?=? /x)
179
181
  if match !~ / [.\)\]\}] /x or match =~ /\.\.\.?/
180
182
  value_expected = :set
181
183
  end
182
- last_token_dot = :set if match == '.' or match == '::'
184
+ last_token_dot = :set if self[1]
183
185
  kind = :operator
184
186
  unless inline_block_stack.empty?
185
187
  case match
@@ -210,8 +212,9 @@ module Scanners
210
212
  interpreted = true
211
213
  state = patterns::StringState.new :regexp, interpreted, match
212
214
 
213
- elsif match = scan(/#{patterns::NUMERIC}/o)
214
- kind = if self[1] then :float else :integer end
215
+ # elsif match = scan(/[-+]?#{patterns::NUMERIC}/o)
216
+ elsif match = value_expected ? scan(/[-+]?#{patterns::NUMERIC}/o) : scan(/#{patterns::NUMERIC}/o)
217
+ kind = self[1] ? :float : :integer
215
218
 
216
219
  elsif match = scan(/#{patterns::SYMBOL}/o)
217
220
  case delim = match[1]
@@ -285,6 +288,18 @@ module Scanners
285
288
  next
286
289
  end
287
290
 
291
+ elsif state == :module_expected
292
+ if match = scan(/<</)
293
+ kind = :operator
294
+ else
295
+ state = :initial
296
+ if match = scan(/ (?:#{patterns::IDENT}::)* #{patterns::IDENT} /ox)
297
+ kind = :class
298
+ else
299
+ next
300
+ end
301
+ end
302
+
288
303
  elsif state == :undef_expected
289
304
  state = :undef_comma_expected
290
305
  if match = scan(/#{patterns::METHOD_NAME_EX}/o)
@@ -306,6 +321,15 @@ module Scanners
306
321
  next
307
322
  end
308
323
 
324
+ elsif state == :alias_expected
325
+ if match = scan(/(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/o)
326
+ tokens << [self[1], (self[1][0] == ?: ? :symbol : :method)]
327
+ tokens << [self[2], :space]
328
+ tokens << [self[3], (self[3][0] == ?: ? :symbol : :method)]
329
+ end
330
+ state = :initial
331
+ next
332
+
309
333
  elsif state == :undef_comma_expected
310
334
  if match = scan(/,/)
311
335
  kind = :operator
@@ -315,23 +339,13 @@ module Scanners
315
339
  next
316
340
  end
317
341
 
318
- elsif state == :module_expected
319
- if match = scan(/<</)
320
- kind = :operator
321
- else
322
- state = :initial
323
- if match = scan(/ (?:#{patterns::IDENT}::)* #{patterns::IDENT} /ox)
324
- kind = :class
325
- else
326
- next
327
- end
328
- end
329
-
330
342
  end
331
343
  # }}}
332
-
333
- value_expected = value_expected == :set
334
- last_token_dot = last_token_dot == :set
344
+
345
+ unless kind == :error
346
+ value_expected = value_expected == :set
347
+ last_token_dot = last_token_dot == :set
348
+ end
335
349
 
336
350
  if $DEBUG and not kind
337
351
  raise_inspect 'Error token %p in line %d' %
@@ -14,19 +14,14 @@ module Scanners
14
14
 
15
15
  DEF_KEYWORDS = %w[ def ]
16
16
  UNDEF_KEYWORDS = %w[ undef ]
17
+ ALIAS_KEYWORDS = %w[ alias ]
17
18
  MODULE_KEYWORDS = %w[class module]
18
19
  DEF_NEW_STATE = WordList.new(:initial).
19
20
  add(DEF_KEYWORDS, :def_expected).
20
21
  add(UNDEF_KEYWORDS, :undef_expected).
22
+ add(ALIAS_KEYWORDS, :alias_expected).
21
23
  add(MODULE_KEYWORDS, :module_expected)
22
24
 
23
- IDENTS_ALLOWING_REGEXP = %w[
24
- and or not while until unless if then elsif when sub sub! gsub gsub!
25
- scan slice slice! split
26
- ]
27
- REGEXP_ALLOWED = WordList.new(false).
28
- add(IDENTS_ALLOWING_REGEXP, :set)
29
-
30
25
  PREDEFINED_CONSTANTS = %w[
31
26
  nil true false self
32
27
  DATA ARGV ARGF __FILE__ __LINE__
@@ -41,19 +36,20 @@ module Scanners
41
36
  METHOD_NAME = / #{IDENT} [?!]? /ox
42
37
  METHOD_NAME_OPERATOR = /
43
38
  \*\*? # multiplication and power
44
- | [-+]@? # plus, minus
45
- | [\/%&|^`~] # division, modulo or format strings, &and, |or, ^xor, `system`, tilde
39
+ | [-+~]@? # plus, minus, tilde with and without @
40
+ | [\/%&|^`] # division, modulo or format strings, &and, |or, ^xor, `system`
46
41
  | \[\]=? # array getter and setter
47
42
  | << | >> # append or shift left, shift right
48
43
  | <=?>? | >=? # comparison, rocket operator
49
- | ===? # simple equality and case equality
44
+ | ===? | =~ # simple equality, case equality, match
45
+ | ![~=@]? # negation with and without @, not-equal and not-match
50
46
  /ox
51
47
  METHOD_NAME_EX = / #{IDENT} (?:[?!]|=(?!>))? | #{METHOD_NAME_OPERATOR} /ox
52
48
  INSTANCE_VARIABLE = / @ #{IDENT} /ox
53
49
  CLASS_VARIABLE = / @@ #{IDENT} /ox
54
50
  OBJECT_VARIABLE = / @@? #{IDENT} /ox
55
51
  GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox
56
- PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} |#{OBJECT_VARIABLE} /ox
52
+ PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox
57
53
  VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox
58
54
 
59
55
  QUOTE_TO_TYPE = {
@@ -73,7 +69,7 @@ module Scanners
73
69
  EXPONENT = / [eE] [+-]? #{DECIMAL} /ox
74
70
  FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox
75
71
  FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox
76
- NUMERIC = / [-+]? (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox
72
+ NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox
77
73
 
78
74
  SYMBOL = /
79
75
  :
@@ -83,6 +79,7 @@ module Scanners
83
79
  | ['"]
84
80
  )
85
81
  /ox
82
+ METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox
86
83
 
87
84
  # TODO investigste \M, \c and \C escape sequences
88
85
  # (?: M-\\C-|C-\\M-|M-\\c|c\\M-|c|C-|M-)? (?: \\ (?: [0-7]{3} | x[0-9A-Fa-f]{2} | . ) )
@@ -111,7 +108,7 @@ module Scanners
111
108
  (?:
112
109
  ( [A-Za-z_0-9]+ ) # $2 = delim
113
110
  |
114
- ( ["'`] ) # $3 = quote, type
111
+ ( ["'`\/] ) # $3 = quote, type
115
112
  ( [^\n]*? ) \3 # $4 = delim
116
113
  )
117
114
  /mx
@@ -129,15 +126,14 @@ module Scanners
129
126
  /mx
130
127
 
131
128
  # Checks for a valid value to follow. This enables
132
- # fancy_allowed in method calls.
129
+ # value_expected in method calls without parentheses.
133
130
  VALUE_FOLLOWS = /
134
- \s+
131
+ (?>[ \t\f\v]+)
135
132
  (?:
136
133
  [%\/][^\s=]
137
- |
138
- <<-?\S
139
- |
140
- #{CHARACTER}
134
+ | <<-?\S
135
+ | [-+] \d
136
+ | #{CHARACTER}
141
137
  )
142
138
  /x
143
139
 
@@ -0,0 +1,142 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ # Scheme scanner for CodeRay (by closure).
5
+ # Thanks to murphy for putting CodeRay into public.
6
+ class Scheme < Scanner
7
+
8
+ register_for :scheme
9
+ file_extension 'scm'
10
+
11
+ CORE_FORMS = %w[
12
+ lambda let let* letrec syntax-case define-syntax let-syntax
13
+ letrec-syntax begin define quote if or and cond case do delay
14
+ quasiquote set! cons force call-with-current-continuation call/cc
15
+ ]
16
+
17
+ IDENT_KIND = CaseIgnoringWordList.new(:ident).
18
+ add(CORE_FORMS, :reserved)
19
+
20
+ #IDENTIFIER_INITIAL = /[a-z!@\$%&\*\/\:<=>\?~_\^]/i
21
+ #IDENTIFIER_SUBSEQUENT = /#{IDENTIFIER_INITIAL}|\d|\.|\+|-/
22
+ #IDENTIFIER = /#{IDENTIFIER_INITIAL}#{IDENTIFIER_SUBSEQUENT}*|\+|-|\.{3}/
23
+ IDENTIFIER = /[a-zA-Z!@$%&*\/:<=>?~_^][\w!@$%&*\/:<=>?~^.+\-]*|[+-]|\.\.\./
24
+ DIGIT = /\d/
25
+ DIGIT10 = DIGIT
26
+ DIGIT16 = /[0-9a-f]/i
27
+ DIGIT8 = /[0-7]/
28
+ DIGIT2 = /[01]/
29
+ RADIX16 = /\#x/i
30
+ RADIX8 = /\#o/i
31
+ RADIX2 = /\#b/i
32
+ RADIX10 = /\#d/i
33
+ EXACTNESS = /#i|#e/i
34
+ SIGN = /[\+-]?/
35
+ EXP_MARK = /[esfdl]/i
36
+ EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/
37
+ SUFFIX = /#{EXP}?/
38
+ PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/
39
+ PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/
40
+ PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/
41
+ PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/
42
+ UINT10 = /#{DIGIT10}+#*/
43
+ UINT16 = /#{DIGIT16}+#*/
44
+ UINT8 = /#{DIGIT8}+#*/
45
+ UINT2 = /#{DIGIT2}+#*/
46
+ DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/
47
+ UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/
48
+ UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/
49
+ UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/
50
+ UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/
51
+ REAL10 = /#{SIGN}#{UREAL10}/
52
+ REAL16 = /#{SIGN}#{UREAL16}/
53
+ REAL8 = /#{SIGN}#{UREAL8}/
54
+ REAL2 = /#{SIGN}#{UREAL2}/
55
+ IMAG10 = /i|#{UREAL10}i/
56
+ IMAG16 = /i|#{UREAL16}i/
57
+ IMAG8 = /i|#{UREAL8}i/
58
+ IMAG2 = /i|#{UREAL2}i/
59
+ COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/
60
+ COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/
61
+ COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/
62
+ COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/
63
+ NUM10 = /#{PREFIX10}?#{COMPLEX10}/
64
+ NUM16 = /#{PREFIX16}#{COMPLEX16}/
65
+ NUM8 = /#{PREFIX8}#{COMPLEX8}/
66
+ NUM2 = /#{PREFIX2}#{COMPLEX2}/
67
+ NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/
68
+
69
+ private
70
+ def scan_tokens tokens,options
71
+
72
+ state = :initial
73
+ ident_kind = IDENT_KIND
74
+
75
+ until eos?
76
+ kind = match = nil
77
+
78
+ case state
79
+ when :initial
80
+ if scan(/ \s+ | \\\n /x)
81
+ kind = :space
82
+ elsif scan(/['\(\[\)\]]|#\(/)
83
+ kind = :operator_fat
84
+ elsif scan(/;.*/)
85
+ kind = :comment
86
+ elsif scan(/#\\(?:newline|space|.?)/)
87
+ kind = :char
88
+ elsif scan(/#[ft]/)
89
+ kind = :pre_constant
90
+ elsif scan(/#{IDENTIFIER}/o)
91
+ kind = ident_kind[matched]
92
+ elsif scan(/\./)
93
+ kind = :operator
94
+ elsif scan(/"/)
95
+ tokens << [:open, :string]
96
+ state = :string
97
+ tokens << ['"', :delimiter]
98
+ next
99
+ elsif scan(/#{NUM}/o) and not matched.empty?
100
+ kind = :integer
101
+ elsif getch
102
+ kind = :error
103
+ end
104
+
105
+ when :string
106
+ if scan(/[^"\\]+/) or scan(/\\.?/)
107
+ kind = :content
108
+ elsif scan(/"/)
109
+ tokens << ['"', :delimiter]
110
+ tokens << [:close, :string]
111
+ state = :initial
112
+ next
113
+ else
114
+ raise_inspect "else case \" reached; %p not handled." % peek(1),
115
+ tokens, state
116
+ end
117
+
118
+ else
119
+ raise "else case reached"
120
+ end
121
+
122
+ match ||= matched
123
+ if $DEBUG and not kind
124
+ raise_inspect 'Error token %p in line %d' %
125
+ [[match, kind], line], tokens
126
+ end
127
+ raise_inspect 'Empty token', tokens, state unless match
128
+
129
+ tokens << [match, kind]
130
+
131
+ end # until eos
132
+
133
+ if state == :string
134
+ tokens << [:close, :string]
135
+ end
136
+
137
+ tokens
138
+
139
+ end #scan_tokens
140
+ end #class
141
+ end #module scanners
142
+ end #module coderay