raldred-coderay 0.9.0 → 0.9.339

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 (58) hide show
  1. data/lib/README +128 -0
  2. data/lib/coderay.rb +319 -0
  3. data/lib/coderay/duo.rb +85 -0
  4. data/lib/coderay/encoder.rb +187 -0
  5. data/lib/coderay/encoders/_map.rb +9 -0
  6. data/lib/coderay/encoders/count.rb +21 -0
  7. data/lib/coderay/encoders/debug.rb +49 -0
  8. data/lib/coderay/encoders/div.rb +20 -0
  9. data/lib/coderay/encoders/html.rb +306 -0
  10. data/lib/coderay/encoders/html/css.rb +70 -0
  11. data/lib/coderay/encoders/html/numerization.rb +133 -0
  12. data/lib/coderay/encoders/html/output.rb +206 -0
  13. data/lib/coderay/encoders/json.rb +19 -0
  14. data/lib/coderay/encoders/null.rb +26 -0
  15. data/lib/coderay/encoders/page.rb +21 -0
  16. data/lib/coderay/encoders/span.rb +20 -0
  17. data/lib/coderay/encoders/statistic.rb +77 -0
  18. data/lib/coderay/encoders/term.rb +114 -0
  19. data/lib/coderay/encoders/text.rb +32 -0
  20. data/lib/coderay/encoders/tokens.rb +44 -0
  21. data/lib/coderay/encoders/xml.rb +71 -0
  22. data/lib/coderay/encoders/yaml.rb +22 -0
  23. data/lib/coderay/for_redcloth.rb +73 -0
  24. data/lib/coderay/helpers/file_type.rb +226 -0
  25. data/lib/coderay/helpers/gzip_simple.rb +123 -0
  26. data/lib/coderay/helpers/plugin.rb +339 -0
  27. data/lib/coderay/helpers/word_list.rb +124 -0
  28. data/lib/coderay/scanner.rb +271 -0
  29. data/lib/coderay/scanners/_map.rb +21 -0
  30. data/lib/coderay/scanners/c.rb +166 -0
  31. data/lib/coderay/scanners/css.rb +202 -0
  32. data/lib/coderay/scanners/debug.rb +61 -0
  33. data/lib/coderay/scanners/delphi.rb +150 -0
  34. data/lib/coderay/scanners/diff.rb +104 -0
  35. data/lib/coderay/scanners/groovy.rb +271 -0
  36. data/lib/coderay/scanners/html.rb +175 -0
  37. data/lib/coderay/scanners/java.rb +173 -0
  38. data/lib/coderay/scanners/java/builtin_types.rb +419 -0
  39. data/lib/coderay/scanners/java_script.rb +195 -0
  40. data/lib/coderay/scanners/json.rb +107 -0
  41. data/lib/coderay/scanners/nitro_xhtml.rb +132 -0
  42. data/lib/coderay/scanners/php.rb +404 -0
  43. data/lib/coderay/scanners/plaintext.rb +18 -0
  44. data/lib/coderay/scanners/python.rb +232 -0
  45. data/lib/coderay/scanners/rhtml.rb +71 -0
  46. data/lib/coderay/scanners/ruby.rb +386 -0
  47. data/lib/coderay/scanners/ruby/patterns.rb +232 -0
  48. data/lib/coderay/scanners/scheme.rb +142 -0
  49. data/lib/coderay/scanners/sql.rb +162 -0
  50. data/lib/coderay/scanners/xml.rb +17 -0
  51. data/lib/coderay/scanners/yaml.rb +142 -0
  52. data/lib/coderay/style.rb +20 -0
  53. data/lib/coderay/styles/_map.rb +7 -0
  54. data/lib/coderay/styles/cycnus.rb +151 -0
  55. data/lib/coderay/styles/murphy.rb +132 -0
  56. data/lib/coderay/token_classes.rb +86 -0
  57. data/lib/coderay/tokens.rb +387 -0
  58. metadata +59 -1
@@ -0,0 +1,232 @@
1
+ module CodeRay
2
+ module Scanners
3
+
4
+ module Ruby::Patterns # :nodoc:
5
+
6
+ RESERVED_WORDS = %w[
7
+ and def end in or unless begin
8
+ defined? ensure module redo super until
9
+ BEGIN break do next rescue then
10
+ when END case else for retry
11
+ while alias class elsif if not return
12
+ undef yield
13
+ ]
14
+
15
+ DEF_KEYWORDS = %w[ def ]
16
+ UNDEF_KEYWORDS = %w[ undef ]
17
+ ALIAS_KEYWORDS = %w[ alias ]
18
+ MODULE_KEYWORDS = %w[class module]
19
+ DEF_NEW_STATE = WordList.new(:initial).
20
+ add(DEF_KEYWORDS, :def_expected).
21
+ add(UNDEF_KEYWORDS, :undef_expected).
22
+ add(ALIAS_KEYWORDS, :alias_expected).
23
+ add(MODULE_KEYWORDS, :module_expected)
24
+
25
+ PREDEFINED_CONSTANTS = %w[
26
+ nil true false self
27
+ DATA ARGV ARGF __FILE__ __LINE__
28
+ ]
29
+
30
+ IDENT_KIND = WordList.new(:ident).
31
+ add(RESERVED_WORDS, :reserved).
32
+ add(PREDEFINED_CONSTANTS, :pre_constant)
33
+
34
+ IDENT = /[a-z_][\w_]*/i
35
+
36
+ METHOD_NAME = / #{IDENT} [?!]? /ox
37
+ METHOD_NAME_OPERATOR = /
38
+ \*\*? # multiplication and power
39
+ | [-+~]@? # plus, minus, tilde with and without @
40
+ | [\/%&|^`] # division, modulo or format strings, &and, |or, ^xor, `system`
41
+ | \[\]=? # array getter and setter
42
+ | << | >> # append or shift left, shift right
43
+ | <=?>? | >=? # comparison, rocket operator
44
+ | ===? | =~ # simple equality, case equality, match
45
+ | ![~=@]? # negation with and without @, not-equal and not-match
46
+ /ox
47
+ METHOD_NAME_EX = / #{IDENT} (?:[?!]|=(?!>))? | #{METHOD_NAME_OPERATOR} /ox
48
+ INSTANCE_VARIABLE = / @ #{IDENT} /ox
49
+ CLASS_VARIABLE = / @@ #{IDENT} /ox
50
+ OBJECT_VARIABLE = / @@? #{IDENT} /ox
51
+ GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox
52
+ PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox
53
+ VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox
54
+
55
+ QUOTE_TO_TYPE = {
56
+ '`' => :shell,
57
+ '/'=> :regexp,
58
+ }
59
+ QUOTE_TO_TYPE.default = :string
60
+
61
+ REGEXP_MODIFIERS = /[mixounse]*/
62
+ REGEXP_SYMBOLS = /[|?*+?(){}\[\].^$]/
63
+
64
+ DECIMAL = /\d+(?:_\d+)*/
65
+ OCTAL = /0_?[0-7]+(?:_[0-7]+)*/
66
+ HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/
67
+ BINARY = /0b[01]+(?:_[01]+)*/
68
+
69
+ EXPONENT = / [eE] [+-]? #{DECIMAL} /ox
70
+ FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox
71
+ FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox
72
+ NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox
73
+
74
+ SYMBOL = /
75
+ :
76
+ (?:
77
+ #{METHOD_NAME_EX}
78
+ | #{PREFIX_VARIABLE}
79
+ | ['"]
80
+ )
81
+ /ox
82
+ METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox
83
+
84
+ SIMPLE_ESCAPE = /
85
+ [abefnrstv]
86
+ | [0-7]{1,3}
87
+ | x[0-9A-Fa-f]{1,2}
88
+ | .?
89
+ /mx
90
+
91
+ CONTROL_META_ESCAPE = /
92
+ (?: M-|C-|c )
93
+ (?: \\ (?: M-|C-|c ) )*
94
+ (?: [^\\] | \\ #{SIMPLE_ESCAPE} )?
95
+ /mox
96
+
97
+ ESCAPE = /
98
+ #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE}
99
+ /mox
100
+
101
+ CHARACTER = /
102
+ \?
103
+ (?:
104
+ [^\s\\]
105
+ | \\ #{ESCAPE}
106
+ )
107
+ /mox
108
+
109
+ # NOTE: This is not completely correct, but
110
+ # nobody needs heredoc delimiters ending with \n.
111
+ HEREDOC_OPEN = /
112
+ << (-)? # $1 = float
113
+ (?:
114
+ ( [A-Za-z_0-9]+ ) # $2 = delim
115
+ |
116
+ ( ["'`\/] ) # $3 = quote, type
117
+ ( [^\n]*? ) \3 # $4 = delim
118
+ )
119
+ /mx
120
+
121
+ RUBYDOC = /
122
+ =begin (?!\S)
123
+ .*?
124
+ (?: \Z | ^=end (?!\S) [^\n]* )
125
+ /mx
126
+
127
+ DATA = /
128
+ __END__$
129
+ .*?
130
+ (?: \Z | (?=^\#CODE) )
131
+ /mx
132
+
133
+ # Checks for a valid value to follow. This enables
134
+ # value_expected in method calls without parentheses.
135
+ VALUE_FOLLOWS = /
136
+ (?>[ \t\f\v]+)
137
+ (?:
138
+ [%\/][^\s=]
139
+ | <<-?\S
140
+ | [-+] \d
141
+ | #{CHARACTER}
142
+ )
143
+ /x
144
+
145
+ RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo
146
+
147
+ RDOC_DATA_START = / ^=begin (?!\S) | ^__END__$ /x
148
+
149
+ # FIXME: \s and = are only a workaround, they are still allowed
150
+ # as delimiters.
151
+ FANCY_START_SAVE = / % ( [qQwWxsr] | (?![a-zA-Z0-9\s=]) ) ([^a-zA-Z0-9]) /mx
152
+ FANCY_START_CORRECT = / % ( [qQwWxsr] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /mx
153
+
154
+ FancyStringType = {
155
+ 'q' => [:string, false],
156
+ 'Q' => [:string, true],
157
+ 'r' => [:regexp, true],
158
+ 's' => [:symbol, false],
159
+ 'x' => [:shell, true]
160
+ }
161
+ FancyStringType['w'] = FancyStringType['q']
162
+ FancyStringType['W'] = FancyStringType[''] = FancyStringType['Q']
163
+
164
+ class StringState < Struct.new :type, :interpreted, :delim, :heredoc,
165
+ :paren, :paren_depth, :pattern, :next_state
166
+
167
+ CLOSING_PAREN = Hash[ *%w[
168
+ ( )
169
+ [ ]
170
+ < >
171
+ { }
172
+ ] ]
173
+
174
+ CLOSING_PAREN.each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with <<
175
+ OPENING_PAREN = CLOSING_PAREN.invert
176
+
177
+ STRING_PATTERN = Hash.new { |h, k|
178
+ delim, interpreted = *k
179
+ delim_pattern = Regexp.escape(delim)
180
+ if closing_paren = CLOSING_PAREN[delim]
181
+ delim_pattern = delim_pattern[0..-1] if defined? JRUBY_VERSION # JRuby fix
182
+ delim_pattern << Regexp.escape(closing_paren)
183
+ end
184
+
185
+
186
+ special_escapes =
187
+ case interpreted
188
+ when :regexp_symbols
189
+ '| ' + REGEXP_SYMBOLS.source
190
+ when :words
191
+ '| \s'
192
+ end
193
+
194
+ h[k] =
195
+ if interpreted and not delim == '#'
196
+ / (?= [#{delim_pattern}\\] | \# [{$@] #{special_escapes} ) /mx
197
+ else
198
+ / (?= [#{delim_pattern}\\] #{special_escapes} ) /mx
199
+ end
200
+ }
201
+
202
+ HEREDOC_PATTERN = Hash.new { |h, k|
203
+ delim, interpreted, indented = *k
204
+ delim_pattern = Regexp.escape(delim.dup)
205
+ delim_pattern = / \n #{ '(?>[\ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x
206
+ h[k] =
207
+ if interpreted
208
+ / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc
209
+ else
210
+ / (?= #{delim_pattern}() | \\ ) /mx
211
+ end
212
+ }
213
+
214
+ def initialize kind, interpreted, delim, heredoc = false
215
+ if heredoc
216
+ pattern = HEREDOC_PATTERN[ [delim, interpreted, heredoc == :indented] ]
217
+ delim = nil
218
+ else
219
+ pattern = STRING_PATTERN[ [delim, interpreted] ]
220
+ if paren = CLOSING_PAREN[delim]
221
+ delim, paren = paren, delim
222
+ paren_depth = 1
223
+ end
224
+ end
225
+ super kind, interpreted, delim, heredoc, paren, paren_depth, pattern, :initial
226
+ end
227
+ end unless defined? StringState
228
+
229
+ end
230
+
231
+ end
232
+ end
@@ -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
@@ -0,0 +1,162 @@
1
+ module CodeRay module Scanners
2
+
3
+ # by Josh Goebel
4
+ class SQL < Scanner
5
+
6
+ register_for :sql
7
+
8
+ RESERVED_WORDS = %w(
9
+ create table index trigger drop primary key set select
10
+ insert update delete replace into
11
+ on from values before and or if exists case when
12
+ then else as group order by avg where
13
+ join inner outer union engine not
14
+ like end using collate show columns begin
15
+ )
16
+
17
+ PREDEFINED_TYPES = %w(
18
+ char varchar enum binary text tinytext mediumtext
19
+ longtext blob tinyblob mediumblob longblob timestamp
20
+ date time datetime year double decimal float int
21
+ integer tinyint mediumint bigint smallint unsigned bit
22
+ bool boolean hex bin oct
23
+ )
24
+
25
+ PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg )
26
+
27
+ DIRECTIVES = %w( auto_increment unique default charset )
28
+
29
+ PREDEFINED_CONSTANTS = %w( null true false )
30
+
31
+ IDENT_KIND = CaseIgnoringWordList.new(:ident).
32
+ add(RESERVED_WORDS, :reserved).
33
+ add(PREDEFINED_TYPES, :pre_type).
34
+ add(PREDEFINED_CONSTANTS, :pre_constant).
35
+ add(PREDEFINED_FUNCTIONS, :predefined).
36
+ add(DIRECTIVES, :directive)
37
+
38
+ ESCAPE = / [rbfnrtv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
39
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
40
+
41
+ STRING_PREFIXES = /[xnb]|_\w+/i
42
+
43
+ def scan_tokens tokens, options
44
+
45
+ state = :initial
46
+ string_type = nil
47
+ string_content = ''
48
+
49
+ until eos?
50
+
51
+ kind = nil
52
+ match = nil
53
+
54
+ if state == :initial
55
+
56
+ if scan(/ \s+ | \\\n /x)
57
+ kind = :space
58
+
59
+ elsif scan(/^(?:--\s?|#).*/)
60
+ kind = :comment
61
+
62
+ elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx)
63
+ kind = :comment
64
+
65
+ elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x)
66
+ kind = :operator
67
+
68
+ elsif scan(/(#{STRING_PREFIXES})?([`"'])/o)
69
+ prefix = self[1]
70
+ string_type = self[2]
71
+ tokens << [:open, :string]
72
+ tokens << [prefix, :modifier] if prefix
73
+ match = string_type
74
+ state = :string
75
+ kind = :delimiter
76
+
77
+ elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
78
+ kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase]
79
+
80
+ elsif scan(/0[xX][0-9A-Fa-f]+/)
81
+ kind = :hex
82
+
83
+ elsif scan(/0[0-7]+(?![89.eEfF])/)
84
+ kind = :oct
85
+
86
+ elsif scan(/(?>\d+)(?![.eEfF])/)
87
+ kind = :integer
88
+
89
+ elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
90
+ kind = :float
91
+
92
+ else
93
+ getch
94
+ kind = :error
95
+
96
+ end
97
+
98
+ elsif state == :string
99
+ if match = scan(/[^\\"'`]+/)
100
+ string_content << match
101
+ next
102
+ elsif match = scan(/["'`]/)
103
+ if string_type == match
104
+ if peek(1) == string_type # doubling means escape
105
+ string_content << string_type << getch
106
+ next
107
+ end
108
+ unless string_content.empty?
109
+ tokens << [string_content, :content]
110
+ string_content = ''
111
+ end
112
+ tokens << [matched, :delimiter]
113
+ tokens << [:close, :string]
114
+ state = :initial
115
+ string_type = nil
116
+ next
117
+ else
118
+ string_content << match
119
+ end
120
+ next
121
+ elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
122
+ unless string_content.empty?
123
+ tokens << [string_content, :content]
124
+ string_content = ''
125
+ end
126
+ kind = :char
127
+ elsif match = scan(/ \\ . /mox)
128
+ string_content << match
129
+ next
130
+ elsif scan(/ \\ | $ /x)
131
+ unless string_content.empty?
132
+ tokens << [string_content, :content]
133
+ string_content = ''
134
+ end
135
+ kind = :error
136
+ state = :initial
137
+ else
138
+ raise "else case \" reached; %p not handled." % peek(1), tokens
139
+ end
140
+
141
+ else
142
+ raise 'else-case reached', tokens
143
+
144
+ end
145
+
146
+ match ||= matched
147
+ unless kind
148
+ raise_inspect 'Error token %p in line %d' %
149
+ [[match, kind], line], tokens, state
150
+ end
151
+ raise_inspect 'Empty token', tokens unless match
152
+
153
+ tokens << [match, kind]
154
+
155
+ end
156
+ tokens
157
+
158
+ end
159
+
160
+ end
161
+
162
+ end end