rdoc 2.4.3 → 2.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (139) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +3 -1
  3. data/History.txt +68 -0
  4. data/LICENSE.txt +57 -0
  5. data/Manifest.txt +37 -19
  6. data/README.txt +2 -12
  7. data/Rakefile +12 -12
  8. data/bin/rdoc +4 -4
  9. data/lib/rdoc.rb +32 -9
  10. data/lib/rdoc/alias.rb +2 -2
  11. data/lib/rdoc/any_method.rb +108 -16
  12. data/lib/rdoc/attr.rb +87 -1
  13. data/lib/rdoc/class_module.rb +131 -5
  14. data/lib/rdoc/code_object.rb +28 -5
  15. data/lib/rdoc/constant.rb +22 -0
  16. data/lib/rdoc/context.rb +80 -37
  17. data/lib/rdoc/gauntlet.rb +48 -0
  18. data/lib/rdoc/generator/darkfish.rb +25 -23
  19. data/lib/rdoc/generator/markup.rb +6 -29
  20. data/lib/rdoc/generator/ri.rb +39 -189
  21. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +17 -1
  22. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +10 -0
  23. data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
  24. data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
  25. data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
  26. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
  27. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
  28. data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
  29. data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
  30. data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
  31. data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
  32. data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
  33. data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
  34. data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
  35. data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
  36. data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
  37. data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
  38. data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
  39. data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
  40. data/lib/rdoc/generator/template/darkfish/index.rhtml +2 -2
  41. data/lib/rdoc/generator/template/darkfish/rdoc.css +38 -33
  42. data/lib/rdoc/include.rb +22 -0
  43. data/lib/rdoc/markup.rb +10 -262
  44. data/lib/rdoc/markup/attribute_manager.rb +57 -50
  45. data/lib/rdoc/markup/blank_line.rb +19 -0
  46. data/lib/rdoc/markup/document.rb +72 -0
  47. data/lib/rdoc/markup/formatter.rb +118 -0
  48. data/lib/rdoc/markup/formatter_test_case.rb +341 -0
  49. data/lib/rdoc/markup/heading.rb +17 -0
  50. data/lib/rdoc/markup/inline.rb +6 -5
  51. data/lib/rdoc/markup/list.rb +78 -0
  52. data/lib/rdoc/markup/list_item.rb +83 -0
  53. data/lib/rdoc/markup/paragraph.rb +66 -0
  54. data/lib/rdoc/markup/parser.rb +528 -0
  55. data/lib/rdoc/markup/rule.rb +17 -0
  56. data/lib/rdoc/markup/to_ansi.rb +72 -0
  57. data/lib/rdoc/markup/to_bs.rb +74 -0
  58. data/lib/rdoc/markup/to_html.rb +106 -172
  59. data/lib/rdoc/markup/to_html_crossref.rb +10 -4
  60. data/lib/rdoc/markup/to_rdoc.rb +243 -0
  61. data/lib/rdoc/markup/to_test.rb +27 -16
  62. data/lib/rdoc/markup/verbatim.rb +42 -0
  63. data/lib/rdoc/normal_class.rb +38 -1
  64. data/lib/rdoc/normal_module.rb +38 -8
  65. data/lib/rdoc/options.rb +39 -151
  66. data/lib/rdoc/parser.rb +36 -18
  67. data/lib/rdoc/parser/c.rb +102 -109
  68. data/lib/rdoc/parser/ruby.rb +359 -1662
  69. data/lib/rdoc/parser/ruby_tools.rb +157 -0
  70. data/lib/rdoc/parser/simple.rb +0 -2
  71. data/lib/rdoc/rdoc.rb +142 -82
  72. data/lib/rdoc/ri.rb +10 -0
  73. data/lib/rdoc/ri/driver.rb +674 -444
  74. data/lib/rdoc/ri/formatter.rb +2 -651
  75. data/lib/rdoc/ri/paths.rb +70 -45
  76. data/lib/rdoc/ri/store.rb +248 -0
  77. data/lib/rdoc/ruby_lex.rb +1284 -0
  78. data/lib/rdoc/ruby_token.rb +416 -0
  79. data/lib/rdoc/single_class.rb +5 -0
  80. data/lib/rdoc/stats.rb +152 -83
  81. data/lib/rdoc/task.rb +27 -49
  82. data/lib/rdoc/text.rb +130 -0
  83. data/lib/rdoc/tokenstream.rb +28 -9
  84. data/lib/rdoc/top_level.rb +49 -43
  85. data/test/hidden.zip.txt +1 -0
  86. data/test/test_attribute_manager.rb +9 -16
  87. data/test/test_rdoc_any_method.rb +23 -0
  88. data/test/test_rdoc_attr.rb +40 -0
  89. data/test/test_rdoc_class_module.rb +100 -0
  90. data/test/test_rdoc_code_object.rb +18 -2
  91. data/test/test_rdoc_context.rb +41 -0
  92. data/test/test_rdoc_generator_ri.rb +56 -0
  93. data/test/test_rdoc_markup.rb +21 -610
  94. data/test/test_rdoc_markup_attribute_manager.rb +14 -17
  95. data/test/test_rdoc_markup_document.rb +51 -0
  96. data/test/test_rdoc_markup_paragraph.rb +27 -0
  97. data/test/test_rdoc_markup_parser.rb +1327 -0
  98. data/test/test_rdoc_markup_to_ansi.rb +426 -0
  99. data/test/test_rdoc_markup_to_bs.rb +443 -0
  100. data/test/test_rdoc_markup_to_html.rb +183 -18
  101. data/test/test_rdoc_markup_to_html_crossref.rb +1 -3
  102. data/test/test_rdoc_markup_to_rdoc.rb +426 -0
  103. data/test/test_rdoc_normal_class.rb +17 -0
  104. data/test/test_rdoc_normal_module.rb +6 -6
  105. data/test/test_rdoc_options.rb +41 -0
  106. data/test/test_rdoc_parser.rb +66 -13
  107. data/test/test_rdoc_parser_c.rb +93 -38
  108. data/test/test_rdoc_parser_perl.rb +2 -3
  109. data/test/test_rdoc_parser_ruby.rb +291 -28
  110. data/test/test_rdoc_parser_simple.rb +48 -0
  111. data/test/test_rdoc_rdoc.rb +66 -0
  112. data/test/test_rdoc_ri_driver.rb +752 -38
  113. data/test/test_rdoc_ri_paths.rb +39 -0
  114. data/test/test_rdoc_ri_store.rb +309 -0
  115. data/test/test_rdoc_text.rb +157 -0
  116. data/test/test_rdoc_top_level.rb +35 -9
  117. data/test/xref_data.rb +9 -1
  118. data/test/xref_test_case.rb +8 -3
  119. metadata +110 -38
  120. metadata.gz.sig +0 -0
  121. data/lib/rdoc/cache.rb +0 -41
  122. data/lib/rdoc/diagram.rb +0 -340
  123. data/lib/rdoc/dot.rb +0 -249
  124. data/lib/rdoc/markup/fragments.rb +0 -377
  125. data/lib/rdoc/markup/lines.rb +0 -156
  126. data/lib/rdoc/markup/to_flow.rb +0 -211
  127. data/lib/rdoc/markup/to_latex.rb +0 -328
  128. data/lib/rdoc/markup/to_texinfo.rb +0 -73
  129. data/lib/rdoc/ri/cache.rb +0 -187
  130. data/lib/rdoc/ri/descriptions.rb +0 -156
  131. data/lib/rdoc/ri/display.rb +0 -340
  132. data/lib/rdoc/ri/reader.rb +0 -106
  133. data/lib/rdoc/ri/util.rb +0 -79
  134. data/lib/rdoc/ri/writer.rb +0 -68
  135. data/test/test_rdoc_ri_attribute_formatter.rb +0 -44
  136. data/test/test_rdoc_ri_default_display.rb +0 -302
  137. data/test/test_rdoc_ri_formatter.rb +0 -320
  138. data/test/test_rdoc_ri_html_formatter.rb +0 -141
  139. data/test/test_rdoc_ri_overstrike_formatter.rb +0 -71
@@ -1,45 +1,63 @@
1
1
  require 'rdoc/ri'
2
2
 
3
3
  ##
4
- # Encapsulate all the strangeness to do with finding out where to find RDoc
5
- # files
6
- #
7
- # We basically deal with three directories:
8
- #
9
- # 1. The 'system' documentation directory, which holds the documentation
10
- # distributed with Ruby, and which is managed by the Ruby install process
11
- # 2. The 'site' directory, which contains site-wide documentation added
12
- # locally.
13
- # 3. The 'user' documentation directory, stored under the user's own home
14
- # directory.
15
- #
16
- # There's contention about all this, but for now:
17
- #
18
- # system:: $datadir/ri/<ver>/system/...
19
- # site:: $datadir/ri/<ver>/site/...
20
- # user:: ~/.rdoc
4
+ # The directories where ri data lives.
21
5
 
22
6
  module RDoc::RI::Paths
23
7
 
24
8
  #:stopdoc:
25
9
  require 'rbconfig'
26
10
 
27
- DOC_DIR = "doc/rdoc"
11
+ version = RbConfig::CONFIG['ruby_version']
12
+
13
+ base = File.join RbConfig::CONFIG['datadir'], "ri", version
14
+ SYSDIR = File.join base, "system"
15
+ SITEDIR = File.join base, "site"
16
+ homedir = File.expand_path('~') ||
17
+ ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
18
+
19
+ HOMEDIR = if homedir then
20
+ File.join homedir, ".rdoc"
21
+ end
22
+ #:startdoc:
23
+
24
+ @gemdirs = nil
25
+
26
+ ##
27
+ # Iterates over each selected path yielding the directory and type.
28
+ #
29
+ # Yielded types:
30
+ # :system:: Where Ruby's ri data is stored. Yielded when +system+ is
31
+ # true
32
+ # :site:: Where ri for installed libraries are stored. Yielded when
33
+ # +site+ is true. Normally no ri data is stored here.
34
+ # :home:: ~/.ri. Yielded when +home+ is true.
35
+ # :gem:: ri data for an installed gem. Yielded when +gems+ is true.
36
+ # :extra:: ri data directory from the command line. Yielded for each
37
+ # entry in +extra_dirs+
38
+
39
+ def self.each system, site, home, gems, *extra_dirs # :yields: directory, type
40
+ extra_dirs.each do |dir|
41
+ yield dir, :extra
42
+ end
28
43
 
29
- VERSION = RbConfig::CONFIG['ruby_version']
44
+ yield SYSDIR, :system if system
45
+ yield SITEDIR, :site if site
46
+ yield HOMEDIR, :home if home
30
47
 
31
- base = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION)
32
- SYSDIR = File.join(base, "system")
33
- SITEDIR = File.join(base, "site")
34
- homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
48
+ gemdirs.each do |dir|
49
+ yield dir, :gem
50
+ end if gems
35
51
 
36
- if homedir then
37
- HOMEDIR = File.join(homedir, ".rdoc")
38
- else
39
- HOMEDIR = nil
52
+ nil
40
53
  end
41
54
 
42
- begin
55
+ ##
56
+ # The latest installed gems' ri directories
57
+
58
+ def self.gemdirs
59
+ return @gemdirs if @gemdirs
60
+
43
61
  require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and
44
62
  Gem::Enable
45
63
 
@@ -63,31 +81,38 @@ module RDoc::RI::Paths
63
81
  end
64
82
  end
65
83
 
66
- GEMDIRS = ri_paths.map { |k,v| v.last }.sort
84
+ @gemdirs = ri_paths.map { |k,v| v.last }.sort
67
85
  rescue LoadError
68
- GEMDIRS = []
86
+ @gemdirs = []
69
87
  end
70
88
 
71
- # Returns the selected documentation directories as an Array, or PATH if no
72
- # overriding directories were given.
89
+ ##
90
+ # Returns existing directories from the selected documentation directories
91
+ # as an Array.
92
+ #
93
+ # See also ::each
94
+
95
+ def self.path(system, site, home, gems, *extra_dirs)
96
+ path = raw_path system, site, home, gems, *extra_dirs
73
97
 
74
- def self.path(use_system, use_site, use_home, use_gems, *extra_dirs)
75
- path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
76
- return path.select { |directory| File.directory? directory }
98
+ path.select { |directory| File.directory? directory }
77
99
  end
78
100
 
79
- # Returns the selected documentation directories including nonexistent
80
- # directories. Used to print out what paths were searched if no ri was
81
- # found.
101
+ ##
102
+ # Returns selected documentation directories including nonexistent
103
+ # directories.
104
+ #
105
+ # See also ::each
82
106
 
83
- def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
107
+ def self.raw_path(system, site, home, gems, *extra_dirs)
84
108
  path = []
85
- path << extra_dirs unless extra_dirs.empty?
86
- path << SYSDIR if use_system
87
- path << SITEDIR if use_site
88
- path << HOMEDIR if use_home
89
- path << GEMDIRS if use_gems
90
109
 
91
- return path.flatten.compact
110
+ each(system, site, home, gems, *extra_dirs) do |dir, type|
111
+ path << dir
112
+ end
113
+
114
+ path.compact
92
115
  end
116
+
93
117
  end
118
+
@@ -0,0 +1,248 @@
1
+ require 'rdoc/code_objects'
2
+ require 'fileutils'
3
+
4
+ ##
5
+ # A set of ri data.
6
+ #
7
+ # The store manages reading and writing ri data for a project (gem, path,
8
+ # etc.) and maintains a cache of methods, classes and ancestors in the
9
+ # store.
10
+
11
+ class RDoc::RI::Store
12
+
13
+ ##
14
+ # Path this store reads or writes
15
+
16
+ attr_accessor :path
17
+
18
+ ##
19
+ # Type of ri datastore this was loaded from. See RDoc::RI::Driver,
20
+ # RDoc::RI::Paths.
21
+
22
+ attr_accessor :type
23
+
24
+ attr_reader :cache
25
+
26
+ ##
27
+ # Creates a new Store of +type+ that will load or save to +path+
28
+
29
+ def initialize path, type = nil
30
+ @type = type
31
+ @path = path
32
+
33
+ @cache = {
34
+ :class_methods => {},
35
+ :instance_methods => {},
36
+ :attributes => {},
37
+ :modules => [],
38
+ :ancestors => {},
39
+ }
40
+ end
41
+
42
+ ##
43
+ # Ancestors cache accessor. Maps a klass name to an Array of its ancestors
44
+ # in this store. If Foo in this store inherits from Object, Kernel won't be
45
+ # listed (it will be included from ruby's ri store).
46
+
47
+ def ancestors
48
+ @cache[:ancestors]
49
+ end
50
+
51
+ ##
52
+ # Attributes cache accessor. Maps a class to an Array of its attributes.
53
+
54
+ def attributes
55
+ @cache[:attributes]
56
+ end
57
+
58
+ ##
59
+ # Path to the cache file
60
+
61
+ def cache_path
62
+ File.join @path, 'cache.ri'
63
+ end
64
+
65
+ ##
66
+ # Path to the ri data for +klass_name+
67
+
68
+ def class_file klass_name
69
+ name = klass_name.split('::').last
70
+ File.join class_path(klass_name), "cdesc-#{name}.ri"
71
+ end
72
+
73
+ ##
74
+ # Class methods cache accessor. Maps a class to an Array of its class
75
+ # methods (not full name).
76
+
77
+ def class_methods
78
+ @cache[:class_methods]
79
+ end
80
+
81
+ ##
82
+ # Path where data for +klass_name+ will be stored (methods or class data)
83
+
84
+ def class_path klass_name
85
+ File.join @path, *klass_name.split('::')
86
+ end
87
+
88
+ ##
89
+ # Friendly rendition of #path
90
+
91
+ def friendly_path
92
+ case type
93
+ when :gem then
94
+ sep = Regexp.union(*['/', File::ALT_SEPARATOR].compact)
95
+ @path =~ /#{sep}doc#{sep}(.*?)#{sep}ri$/
96
+ "gem #{$1}"
97
+ when :home then '~/.ri'
98
+ when :site then 'ruby site'
99
+ when :system then 'ruby core'
100
+ else @path
101
+ end
102
+ end
103
+
104
+ def inspect # :nodoc:
105
+ "#<%s:0x%x %s %p>" % [self.class, object_id, @path, modules.sort]
106
+ end
107
+
108
+ ##
109
+ # Instance methods cache accessor. Maps a class to an Array of its
110
+ # instance methods (not full name).
111
+
112
+ def instance_methods
113
+ @cache[:instance_methods]
114
+ end
115
+
116
+ ##
117
+ # Loads cache file for this store
118
+
119
+ def load_cache
120
+ open cache_path, 'rb' do |io|
121
+ @cache = Marshal.load io.read
122
+ end
123
+ rescue Errno::ENOENT
124
+ end
125
+
126
+ ##
127
+ # Loads ri data for +klass_name+
128
+
129
+ def load_class klass_name
130
+ open class_file(klass_name), 'rb' do |io|
131
+ Marshal.load io.read
132
+ end
133
+ end
134
+
135
+ ##
136
+ # Loads ri data for +method_name+ in +klass_name+
137
+
138
+ def load_method klass_name, method_name
139
+ open method_file(klass_name, method_name), 'rb' do |io|
140
+ Marshal.load io.read
141
+ end
142
+ end
143
+
144
+ ##
145
+ # Path to the ri data for +method_name+ in +klass_name+
146
+
147
+ def method_file klass_name, method_name
148
+ method_name = method_name.split('::').last
149
+ method_name =~ /#(.*)/
150
+ method_type = $1 ? 'i' : 'c'
151
+ method_name = $1 if $1
152
+
153
+ method_name = if ''.respond_to? :ord then
154
+ method_name.gsub(/\W/) { "%%%02x" % $&[0].ord }
155
+ else
156
+ method_name.gsub(/\W/) { "%%%02x" % $&[0] }
157
+ end
158
+
159
+ File.join class_path(klass_name), "#{method_name}-#{method_type}.ri"
160
+ end
161
+
162
+ ##
163
+ # Modules cache accessor. An Array of all the modules (and classes) in the
164
+ # store.
165
+
166
+ def modules
167
+ @cache[:modules]
168
+ end
169
+
170
+ ##
171
+ # Writes the cache file for this store
172
+
173
+ def save_cache
174
+ # HACK mongrel-1.1.5 documents its files twice
175
+ @cache[:attributes]. each do |_, m| m.uniq!; m.sort! end
176
+ @cache[:class_methods]. each do |_, m| m.uniq!; m.sort! end
177
+ @cache[:instance_methods].each do |_, m| m.uniq!; m.sort! end
178
+
179
+ open cache_path, 'wb' do |io|
180
+ Marshal.dump @cache, io
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Writes the ri data for +klass+
186
+
187
+ def save_class klass
188
+ FileUtils.mkdir_p class_path(klass.full_name)
189
+
190
+ @cache[:modules] << klass.full_name
191
+
192
+ path = class_file klass.full_name
193
+
194
+ begin
195
+ disk_klass = nil
196
+
197
+ open path, 'rb' do |io|
198
+ disk_klass = Marshal.load io.read
199
+ end
200
+
201
+ klass.merge disk_klass
202
+ rescue Errno::ENOENT
203
+ end
204
+
205
+ # BasicObject has no ancestors
206
+ ancestors = klass.ancestors.compact.map do |ancestor|
207
+ # HACK for classes we don't know about (class X < RuntimeError)
208
+ String === ancestor ? ancestor : ancestor.full_name
209
+ end
210
+
211
+ @cache[:ancestors][klass.full_name] ||= []
212
+ @cache[:ancestors][klass.full_name].push(*ancestors)
213
+
214
+ attributes = klass.attributes.map do |attribute|
215
+ "#{attribute.type} #{attribute.name}"
216
+ end
217
+
218
+ unless attributes.empty? then
219
+ @cache[:attributes][klass.full_name] ||= []
220
+ @cache[:attributes][klass.full_name].push(*attributes)
221
+ end
222
+
223
+ open path, 'wb' do |io|
224
+ Marshal.dump klass, io
225
+ end
226
+ end
227
+
228
+ ##
229
+ # Writes the ri data for +method+ on +klass+
230
+
231
+ def save_method klass, method
232
+ FileUtils.mkdir_p class_path(klass.full_name)
233
+
234
+ cache = if method.singleton then
235
+ @cache[:class_methods]
236
+ else
237
+ @cache[:instance_methods]
238
+ end
239
+ cache[klass.full_name] ||= []
240
+ cache[klass.full_name] << method.name
241
+
242
+ open method_file(klass.full_name, method.full_name), 'wb' do |io|
243
+ Marshal.dump method, io
244
+ end
245
+ end
246
+
247
+ end
248
+
@@ -0,0 +1,1284 @@
1
+ #--
2
+ # irb/ruby-lex.rb - ruby lexcal analyzer
3
+ # $Release Version: 0.9.5$
4
+ # $Revision: 17979 $
5
+ # $Date: 2008-07-09 10:17:05 -0700 (Wed, 09 Jul 2008) $
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ #++
9
+
10
+ require "e2mmap"
11
+ require "irb/slex"
12
+ require "rdoc/ruby_token"
13
+ require "stringio"
14
+
15
+ ##
16
+ # Ruby lexer adapted from irb.
17
+ #
18
+ # The internals are not documented because they are scary.
19
+
20
+ class RDoc::RubyLex
21
+
22
+ # :stopdoc:
23
+
24
+ extend Exception2MessageMapper
25
+
26
+ def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
27
+ def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
28
+ def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
29
+ def_exception(:TkReading2TokenDuplicateError,
30
+ "key duplicate(token_n='%s', key='%s')")
31
+ def_exception(:SyntaxError, "%s")
32
+
33
+ def_exception(:TerminateLineInput, "Terminate Line Input")
34
+
35
+ include RDoc::RubyToken
36
+ include IRB
37
+
38
+ attr_reader :continue
39
+ attr_reader :lex_state
40
+ attr_reader :reader
41
+
42
+ class << self
43
+ attr_accessor :debug_level
44
+ end
45
+
46
+ def self.debug?
47
+ @debug_level > 0
48
+ end
49
+
50
+ self.debug_level = 0
51
+
52
+ def initialize(content, options)
53
+ lex_init
54
+
55
+ if /\t/ =~ content then
56
+ tab_width = options.tab_width
57
+ content = content.split(/\n/).map do |line|
58
+ 1 while line.gsub!(/\t+/) {
59
+ ' ' * (tab_width*$&.length - $`.length % tab_width)
60
+ } && $~
61
+ line
62
+ end.join("\n")
63
+ end
64
+
65
+ content << "\n" unless content[-1, 1] == "\n"
66
+
67
+ set_input StringIO.new content
68
+
69
+ @base_char_no = 0
70
+ @char_no = 0
71
+ @exp_line_no = @line_no = 1
72
+ @here_readed = []
73
+ @readed = []
74
+ @rests = []
75
+ @seek = 0
76
+
77
+ @here_header = false
78
+ @indent = 0
79
+ @indent_stack = []
80
+ @lex_state = EXPR_BEG
81
+ @space_seen = false
82
+
83
+ @continue = false
84
+ @line = ""
85
+
86
+ @skip_space = false
87
+ @readed_auto_clean_up = false
88
+ @exception_on_syntax_error = true
89
+
90
+ @prompt = nil
91
+ @prev_seek = nil
92
+ end
93
+
94
+ def inspect # :nodoc:
95
+ "#<%s:0x%x lex_state %p space_seen %p>" % [
96
+ self.class, object_id,
97
+ @lex_state, @space_seen,
98
+ ]
99
+ end
100
+
101
+ attr_accessor :skip_space
102
+ attr_accessor :readed_auto_clean_up
103
+ attr_accessor :exception_on_syntax_error
104
+
105
+ attr_reader :seek
106
+ attr_reader :char_no
107
+ attr_reader :line_no
108
+ attr_reader :indent
109
+
110
+ # io functions
111
+ def set_input(io, p = nil, &block)
112
+ @io = io
113
+ if p.respond_to?(:call)
114
+ @input = p
115
+ elsif block_given?
116
+ @input = block
117
+ else
118
+ @input = Proc.new{@io.gets}
119
+ end
120
+ end
121
+
122
+ def get_readed
123
+ if idx = @readed.reverse.index("\n")
124
+ @base_char_no = idx
125
+ else
126
+ @base_char_no += @readed.size
127
+ end
128
+
129
+ readed = @readed.join("")
130
+ @readed = []
131
+ readed
132
+ end
133
+
134
+ def getc
135
+ while @rests.empty?
136
+ # return nil unless buf_input
137
+ @rests.push nil unless buf_input
138
+ end
139
+ c = @rests.shift
140
+ if @here_header
141
+ @here_readed.push c
142
+ else
143
+ @readed.push c
144
+ end
145
+ @seek += 1
146
+ if c == "\n"
147
+ @line_no += 1
148
+ @char_no = 0
149
+ else
150
+ @char_no += 1
151
+ end
152
+ c
153
+ end
154
+
155
+ def gets
156
+ l = ""
157
+ while c = getc
158
+ l.concat(c)
159
+ break if c == "\n"
160
+ end
161
+ return nil if l == "" and c.nil?
162
+ l
163
+ end
164
+
165
+ def eof?
166
+ @io.eof?
167
+ end
168
+
169
+ def getc_of_rests
170
+ if @rests.empty?
171
+ nil
172
+ else
173
+ getc
174
+ end
175
+ end
176
+
177
+ def ungetc(c = nil)
178
+ if @here_readed.empty?
179
+ c2 = @readed.pop
180
+ else
181
+ c2 = @here_readed.pop
182
+ end
183
+ c = c2 unless c
184
+ @rests.unshift c #c =
185
+ @seek -= 1
186
+ if c == "\n"
187
+ @line_no -= 1
188
+ if idx = @readed.reverse.index("\n")
189
+ @char_no = @readed.size - idx
190
+ else
191
+ @char_no = @base_char_no + @readed.size
192
+ end
193
+ else
194
+ @char_no -= 1
195
+ end
196
+ end
197
+
198
+ def peek_equal?(str)
199
+ chrs = str.split(//)
200
+ until @rests.size >= chrs.size
201
+ return false unless buf_input
202
+ end
203
+ @rests[0, chrs.size] == chrs
204
+ end
205
+
206
+ def peek_match?(regexp)
207
+ while @rests.empty?
208
+ return false unless buf_input
209
+ end
210
+ regexp =~ @rests.join("")
211
+ end
212
+
213
+ def peek(i = 0)
214
+ while @rests.size <= i
215
+ return nil unless buf_input
216
+ end
217
+ @rests[i]
218
+ end
219
+
220
+ def buf_input
221
+ prompt
222
+ line = @input.call
223
+ return nil unless line
224
+ @rests.concat line.split(//)
225
+ true
226
+ end
227
+ private :buf_input
228
+
229
+ def set_prompt(p = nil, &block)
230
+ p = block if block_given?
231
+ if p.respond_to?(:call)
232
+ @prompt = p
233
+ else
234
+ @prompt = Proc.new{print p}
235
+ end
236
+ end
237
+
238
+ def prompt
239
+ if @prompt
240
+ @prompt.call(@ltype, @indent, @continue, @line_no)
241
+ end
242
+ end
243
+
244
+ def initialize_input
245
+ @ltype = nil
246
+ @quoted = nil
247
+ @indent = 0
248
+ @indent_stack = []
249
+ @lex_state = EXPR_BEG
250
+ @space_seen = false
251
+ @here_header = false
252
+
253
+ @continue = false
254
+ prompt
255
+
256
+ @line = ""
257
+ @exp_line_no = @line_no
258
+ end
259
+
260
+ def each_top_level_statement
261
+ initialize_input
262
+ catch(:TERM_INPUT) do
263
+ loop do
264
+ begin
265
+ @continue = false
266
+ prompt
267
+ unless l = lex
268
+ throw :TERM_INPUT if @line == ''
269
+ else
270
+ #p l
271
+ @line.concat l
272
+ if @ltype or @continue or @indent > 0
273
+ next
274
+ end
275
+ end
276
+ if @line != "\n"
277
+ yield @line, @exp_line_no
278
+ end
279
+ break unless l
280
+ @line = ''
281
+ @exp_line_no = @line_no
282
+
283
+ @indent = 0
284
+ @indent_stack = []
285
+ prompt
286
+ rescue TerminateLineInput
287
+ initialize_input
288
+ prompt
289
+ get_readed
290
+ end
291
+ end
292
+ end
293
+ end
294
+
295
+ def lex
296
+ until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) &&
297
+ !@continue or
298
+ tk.nil?)
299
+ #p tk
300
+ #p @lex_state
301
+ #p self
302
+ end
303
+ line = get_readed
304
+ # print self.inspect
305
+ if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil?
306
+ nil
307
+ else
308
+ line
309
+ end
310
+ end
311
+
312
+ def token
313
+ # require "tracer"
314
+ # Tracer.on
315
+ @prev_seek = @seek
316
+ @prev_line_no = @line_no
317
+ @prev_char_no = @char_no
318
+ begin
319
+ begin
320
+ tk = @OP.match(self)
321
+ @space_seen = tk.kind_of?(TkSPACE)
322
+ rescue SyntaxError => e
323
+ raise RDoc::Error, "syntax error: #{e.message}" if
324
+ @exception_on_syntax_error
325
+
326
+ tk = TkError.new(@seek, @line_no, @char_no)
327
+ end
328
+ end while @skip_space and tk.kind_of?(TkSPACE)
329
+
330
+ if @readed_auto_clean_up
331
+ get_readed
332
+ end
333
+ # Tracer.off
334
+ tk
335
+ end
336
+
337
+ ENINDENT_CLAUSE = [
338
+ "case", "class", "def", "do", "for", "if",
339
+ "module", "unless", "until", "while", "begin" #, "when"
340
+ ]
341
+
342
+ DEINDENT_CLAUSE = ["end" #, "when"
343
+ ]
344
+
345
+ PERCENT_LTYPE = {
346
+ "q" => "\'",
347
+ "Q" => "\"",
348
+ "x" => "\`",
349
+ "r" => "/",
350
+ "w" => "]",
351
+ "W" => "]",
352
+ "s" => ":"
353
+ }
354
+
355
+ PERCENT_PAREN = {
356
+ "{" => "}",
357
+ "[" => "]",
358
+ "<" => ">",
359
+ "(" => ")"
360
+ }
361
+
362
+ Ltype2Token = {
363
+ "\'" => TkSTRING,
364
+ "\"" => TkSTRING,
365
+ "\`" => TkXSTRING,
366
+ "/" => TkREGEXP,
367
+ "]" => TkDSTRING,
368
+ ":" => TkSYMBOL
369
+ }
370
+ DLtype2Token = {
371
+ "\"" => TkDSTRING,
372
+ "\`" => TkDXSTRING,
373
+ "/" => TkDREGEXP,
374
+ }
375
+
376
+ def lex_init()
377
+ @OP = IRB::SLex.new
378
+ @OP.def_rules("\0", "\004", "\032") do |op, io|
379
+ Token(TkEND_OF_SCRIPT)
380
+ end
381
+
382
+ @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |op, io|
383
+ @space_seen = true
384
+ str = op
385
+ while (ch = getc) =~ /[ \t\f\r\13]/ do
386
+ str << ch
387
+ end
388
+ ungetc
389
+ Token TkSPACE, str
390
+ end
391
+
392
+ @OP.def_rule("#") do |op, io|
393
+ identify_comment
394
+ end
395
+
396
+ @OP.def_rule("=begin",
397
+ proc{|op, io| @prev_char_no == 0 && peek(0) =~ /\s/}) do
398
+ |op, io|
399
+ @ltype = "="
400
+ res = ''
401
+ until (ch = getc) == "\n" do res << ch end
402
+ until peek_equal?("=end") && peek(4) =~ /\s/ do
403
+ until (ch = getc) == "\n" do res << ch end
404
+ end
405
+ res << gets
406
+ @ltype = nil
407
+ Token(TkRD_COMMENT, res)
408
+ end
409
+
410
+ @OP.def_rule("\n") do |op, io|
411
+ print "\\n\n" if RDoc::RubyLex.debug?
412
+ case @lex_state
413
+ when EXPR_BEG, EXPR_FNAME, EXPR_DOT
414
+ @continue = true
415
+ else
416
+ @continue = false
417
+ @lex_state = EXPR_BEG
418
+ until (@indent_stack.empty? ||
419
+ [TkLPAREN, TkLBRACK, TkLBRACE,
420
+ TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last))
421
+ @indent_stack.pop
422
+ end
423
+ end
424
+ @here_header = false
425
+ @here_readed = []
426
+ Token(TkNL)
427
+ end
428
+
429
+ @OP.def_rules("*", "**",
430
+ "=", "==", "===",
431
+ "=~", "<=>",
432
+ "<", "<=",
433
+ ">", ">=", ">>") do
434
+ |op, io|
435
+ case @lex_state
436
+ when EXPR_FNAME, EXPR_DOT
437
+ @lex_state = EXPR_ARG
438
+ else
439
+ @lex_state = EXPR_BEG
440
+ end
441
+ Token(op)
442
+ end
443
+
444
+ @OP.def_rules("!", "!=", "!~") do
445
+ |op, io|
446
+ @lex_state = EXPR_BEG
447
+ Token(op)
448
+ end
449
+
450
+ @OP.def_rules("<<") do
451
+ |op, io|
452
+ tk = nil
453
+ if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
454
+ (@lex_state != EXPR_ARG || @space_seen)
455
+ c = peek(0)
456
+ if /\S/ =~ c && (/["'`]/ =~ c || /[\w_]/ =~ c || c == "-")
457
+ tk = identify_here_document
458
+ end
459
+ end
460
+ unless tk
461
+ tk = Token(op)
462
+ case @lex_state
463
+ when EXPR_FNAME, EXPR_DOT
464
+ @lex_state = EXPR_ARG
465
+ else
466
+ @lex_state = EXPR_BEG
467
+ end
468
+ end
469
+ tk
470
+ end
471
+
472
+ @OP.def_rules("'", '"') do
473
+ |op, io|
474
+ identify_string(op)
475
+ end
476
+
477
+ @OP.def_rules("`") do
478
+ |op, io|
479
+ if @lex_state == EXPR_FNAME
480
+ @lex_state = EXPR_END
481
+ Token(op)
482
+ else
483
+ identify_string(op)
484
+ end
485
+ end
486
+
487
+ @OP.def_rules('?') do
488
+ |op, io|
489
+ if @lex_state == EXPR_END
490
+ @lex_state = EXPR_BEG
491
+ Token(TkQUESTION)
492
+ else
493
+ ch = getc
494
+ if @lex_state == EXPR_ARG && ch =~ /\s/
495
+ ungetc
496
+ @lex_state = EXPR_BEG;
497
+ Token(TkQUESTION)
498
+ else
499
+ str = ch
500
+ if ch == '\\'
501
+ str << read_escape
502
+ end
503
+ @lex_state = EXPR_END
504
+ str << (ch.respond_to?(:ord) ? ch.ord : ch[0])
505
+ Token(TkINTEGER, str)
506
+ end
507
+ end
508
+ end
509
+
510
+ @OP.def_rules("&", "&&", "|", "||") do
511
+ |op, io|
512
+ @lex_state = EXPR_BEG
513
+ Token(op)
514
+ end
515
+
516
+ @OP.def_rules("+=", "-=", "*=", "**=",
517
+ "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
518
+ |op, io|
519
+ @lex_state = EXPR_BEG
520
+ op =~ /^(.*)=$/
521
+ Token(TkOPASGN, $1)
522
+ end
523
+
524
+ @OP.def_rule("+@", proc{|op, io| @lex_state == EXPR_FNAME}) do
525
+ |op, io|
526
+ @lex_state = EXPR_ARG
527
+ Token(op)
528
+ end
529
+
530
+ @OP.def_rule("-@", proc{|op, io| @lex_state == EXPR_FNAME}) do
531
+ |op, io|
532
+ @lex_state = EXPR_ARG
533
+ Token(op)
534
+ end
535
+
536
+ @OP.def_rules("+", "-") do
537
+ |op, io|
538
+ catch(:RET) do
539
+ if @lex_state == EXPR_ARG
540
+ if @space_seen and peek(0) =~ /[0-9]/
541
+ throw :RET, identify_number
542
+ else
543
+ @lex_state = EXPR_BEG
544
+ end
545
+ elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
546
+ throw :RET, identify_number
547
+ else
548
+ @lex_state = EXPR_BEG
549
+ end
550
+ Token(op)
551
+ end
552
+ end
553
+
554
+ @OP.def_rule(".") do
555
+ |op, io|
556
+ @lex_state = EXPR_BEG
557
+ if peek(0) =~ /[0-9]/
558
+ ungetc
559
+ identify_number
560
+ else
561
+ # for "obj.if" etc.
562
+ @lex_state = EXPR_DOT
563
+ Token(TkDOT)
564
+ end
565
+ end
566
+
567
+ @OP.def_rules("..", "...") do
568
+ |op, io|
569
+ @lex_state = EXPR_BEG
570
+ Token(op)
571
+ end
572
+
573
+ lex_int2
574
+ end
575
+
576
+ def lex_int2
577
+ @OP.def_rules("]", "}", ")") do
578
+ |op, io|
579
+ @lex_state = EXPR_END
580
+ @indent -= 1
581
+ @indent_stack.pop
582
+ Token(op)
583
+ end
584
+
585
+ @OP.def_rule(":") do
586
+ |op, io|
587
+ if @lex_state == EXPR_END || peek(0) =~ /\s/
588
+ @lex_state = EXPR_BEG
589
+ Token(TkCOLON)
590
+ else
591
+ @lex_state = EXPR_FNAME;
592
+ Token(TkSYMBEG)
593
+ end
594
+ end
595
+
596
+ @OP.def_rule("::") do
597
+ |op, io|
598
+ # p @lex_state.id2name, @space_seen
599
+ if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
600
+ @lex_state = EXPR_BEG
601
+ Token(TkCOLON3)
602
+ else
603
+ @lex_state = EXPR_DOT
604
+ Token(TkCOLON2)
605
+ end
606
+ end
607
+
608
+ @OP.def_rule("/") do
609
+ |op, io|
610
+ if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
611
+ identify_string(op)
612
+ elsif peek(0) == '='
613
+ getc
614
+ @lex_state = EXPR_BEG
615
+ Token(TkOPASGN, "/") #/)
616
+ elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
617
+ identify_string(op)
618
+ else
619
+ @lex_state = EXPR_BEG
620
+ Token("/") #/)
621
+ end
622
+ end
623
+
624
+ @OP.def_rules("^") do
625
+ |op, io|
626
+ @lex_state = EXPR_BEG
627
+ Token("^")
628
+ end
629
+
630
+ # @OP.def_rules("^=") do
631
+ # @lex_state = EXPR_BEG
632
+ # Token(OP_ASGN, :^)
633
+ # end
634
+
635
+ @OP.def_rules(",") do
636
+ |op, io|
637
+ @lex_state = EXPR_BEG
638
+ Token(op)
639
+ end
640
+
641
+ @OP.def_rules(";") do
642
+ |op, io|
643
+ @lex_state = EXPR_BEG
644
+ until (@indent_stack.empty? ||
645
+ [TkLPAREN, TkLBRACK, TkLBRACE,
646
+ TkfLPAREN, TkfLBRACK, TkfLBRACE].include?(@indent_stack.last))
647
+ @indent_stack.pop
648
+ end
649
+ Token(op)
650
+ end
651
+
652
+ @OP.def_rule("~") do
653
+ |op, io|
654
+ @lex_state = EXPR_BEG
655
+ Token("~")
656
+ end
657
+
658
+ @OP.def_rule("~@", proc{|op, io| @lex_state == EXPR_FNAME}) do
659
+ |op, io|
660
+ @lex_state = EXPR_BEG
661
+ Token("~")
662
+ end
663
+
664
+ @OP.def_rule("(") do
665
+ |op, io|
666
+ @indent += 1
667
+ if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
668
+ @lex_state = EXPR_BEG
669
+ tk_c = TkfLPAREN
670
+ else
671
+ @lex_state = EXPR_BEG
672
+ tk_c = TkLPAREN
673
+ end
674
+ @indent_stack.push tk_c
675
+ tk = Token(tk_c)
676
+ end
677
+
678
+ @OP.def_rule("[]", proc{|op, io| @lex_state == EXPR_FNAME}) do
679
+ |op, io|
680
+ @lex_state = EXPR_ARG
681
+ Token("[]")
682
+ end
683
+
684
+ @OP.def_rule("[]=", proc{|op, io| @lex_state == EXPR_FNAME}) do
685
+ |op, io|
686
+ @lex_state = EXPR_ARG
687
+ Token("[]=")
688
+ end
689
+
690
+ @OP.def_rule("[") do
691
+ |op, io|
692
+ @indent += 1
693
+ if @lex_state == EXPR_FNAME
694
+ tk_c = TkfLBRACK
695
+ else
696
+ if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
697
+ tk_c = TkLBRACK
698
+ elsif @lex_state == EXPR_ARG && @space_seen
699
+ tk_c = TkLBRACK
700
+ else
701
+ tk_c = TkfLBRACK
702
+ end
703
+ @lex_state = EXPR_BEG
704
+ end
705
+ @indent_stack.push tk_c
706
+ Token(tk_c)
707
+ end
708
+
709
+ @OP.def_rule("{") do
710
+ |op, io|
711
+ @indent += 1
712
+ if @lex_state != EXPR_END && @lex_state != EXPR_ARG
713
+ tk_c = TkLBRACE
714
+ else
715
+ tk_c = TkfLBRACE
716
+ end
717
+ @lex_state = EXPR_BEG
718
+ @indent_stack.push tk_c
719
+ Token(tk_c)
720
+ end
721
+
722
+ @OP.def_rule('\\') do
723
+ |op, io|
724
+ if getc == "\n"
725
+ @space_seen = true
726
+ @continue = true
727
+ Token(TkSPACE)
728
+ else
729
+ ungetc
730
+ Token("\\")
731
+ end
732
+ end
733
+
734
+ @OP.def_rule('%') do
735
+ |op, io|
736
+ if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
737
+ identify_quotation
738
+ elsif peek(0) == '='
739
+ getc
740
+ Token(TkOPASGN, :%)
741
+ elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
742
+ identify_quotation
743
+ else
744
+ @lex_state = EXPR_BEG
745
+ Token("%") #))
746
+ end
747
+ end
748
+
749
+ @OP.def_rule('$') do
750
+ |op, io|
751
+ identify_gvar
752
+ end
753
+
754
+ @OP.def_rule('@') do
755
+ |op, io|
756
+ if peek(0) =~ /[\w@]/
757
+ ungetc
758
+ identify_identifier
759
+ else
760
+ Token("@")
761
+ end
762
+ end
763
+
764
+ # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do
765
+ # |op, io|
766
+ # @indent += 1
767
+ # @lex_state = EXPR_FNAME
768
+ # # @lex_state = EXPR_END
769
+ # # until @rests[0] == "\n" or @rests[0] == ";"
770
+ # # rests.shift
771
+ # # end
772
+ # end
773
+
774
+ @OP.def_rule("_") do
775
+ if peek_match?(/_END__/) and @lex_state == EXPR_BEG then
776
+ Token(TkEND_OF_SCRIPT)
777
+ else
778
+ ungetc
779
+ identify_identifier
780
+ end
781
+ end
782
+
783
+ @OP.def_rule("") do
784
+ |op, io|
785
+ printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
786
+ if peek(0) =~ /[0-9]/
787
+ t = identify_number
788
+ else
789
+ t = identify_identifier
790
+ end
791
+ printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
792
+ t
793
+ end
794
+
795
+ p @OP if RDoc::RubyLex.debug?
796
+ end
797
+
798
+ def identify_gvar
799
+ @lex_state = EXPR_END
800
+
801
+ case ch = getc
802
+ when /[~_*$?!@\/\\;,=:<>".]/ #"
803
+ Token(TkGVAR, "$" + ch)
804
+ when "-"
805
+ Token(TkGVAR, "$-" + getc)
806
+ when "&", "`", "'", "+"
807
+ Token(TkBACK_REF, "$"+ch)
808
+ when /[1-9]/
809
+ ref = ch
810
+ while (ch = getc) =~ /[0-9]/ do ref << ch end
811
+ ungetc
812
+ Token(TkNTH_REF, "$#{ref}")
813
+ when /\w/
814
+ ungetc
815
+ ungetc
816
+ identify_identifier
817
+ else
818
+ ungetc
819
+ Token("$")
820
+ end
821
+ end
822
+
823
+ def identify_identifier
824
+ token = ""
825
+ if peek(0) =~ /[$@]/
826
+ token.concat(c = getc)
827
+ if c == "@" and peek(0) == "@"
828
+ token.concat getc
829
+ end
830
+ end
831
+
832
+ # HACK to avoid a warning the regexp is hidden behind an eval
833
+ # HACK need a better way to detect oniguruma
834
+ @identifier_re ||= if defined? Encoding then
835
+ eval '/[\p{Alnum}_]/u'
836
+ else
837
+ eval '/[\w\x80-\xff]/'
838
+ end
839
+
840
+ while (ch = getc) =~ @identifier_re
841
+ print " :#{ch}: " if RDoc::RubyLex.debug?
842
+ token.concat ch
843
+ end
844
+
845
+ ungetc
846
+
847
+ if (ch == "!" || ch == "?") && token[0,1] =~ /\w/ && peek(0) != "="
848
+ token.concat getc
849
+ end
850
+
851
+ # almost fix token
852
+
853
+ case token
854
+ when /^\$/
855
+ return Token(TkGVAR, token)
856
+ when /^\@\@/
857
+ @lex_state = EXPR_END
858
+ # p Token(TkCVAR, token)
859
+ return Token(TkCVAR, token)
860
+ when /^\@/
861
+ @lex_state = EXPR_END
862
+ return Token(TkIVAR, token)
863
+ end
864
+
865
+ if @lex_state != EXPR_DOT
866
+ print token, "\n" if RDoc::RubyLex.debug?
867
+
868
+ token_c, *trans = TkReading2Token[token]
869
+ if token_c
870
+ # reserved word?
871
+
872
+ if (@lex_state != EXPR_BEG &&
873
+ @lex_state != EXPR_FNAME &&
874
+ trans[1])
875
+ # modifiers
876
+ token_c = TkSymbol2Token[trans[1]]
877
+ @lex_state = trans[0]
878
+ else
879
+ if @lex_state != EXPR_FNAME
880
+ if ENINDENT_CLAUSE.include?(token)
881
+ # check for ``class = val'' etc.
882
+ valid = true
883
+ case token
884
+ when "class"
885
+ valid = false unless peek_match?(/^\s*(<<|\w|::)/)
886
+ when "def"
887
+ valid = false if peek_match?(/^\s*(([+-\/*&\|^]|<<|>>|\|\||\&\&)=|\&\&|\|\|)/)
888
+ when "do"
889
+ valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&)/)
890
+ when *ENINDENT_CLAUSE
891
+ valid = false if peek_match?(/^\s*([+-\/*]?=|\*|<|>|\&|\|)/)
892
+ else
893
+ # no nothing
894
+ end
895
+ if valid
896
+ if token == "do"
897
+ if ![TkFOR, TkWHILE, TkUNTIL].include?(@indent_stack.last)
898
+ @indent += 1
899
+ @indent_stack.push token_c
900
+ end
901
+ else
902
+ @indent += 1
903
+ @indent_stack.push token_c
904
+ end
905
+ end
906
+
907
+ elsif DEINDENT_CLAUSE.include?(token)
908
+ @indent -= 1
909
+ @indent_stack.pop
910
+ end
911
+ @lex_state = trans[0]
912
+ else
913
+ @lex_state = EXPR_END
914
+ end
915
+ end
916
+ return Token(token_c, token)
917
+ end
918
+ end
919
+
920
+ if @lex_state == EXPR_FNAME
921
+ @lex_state = EXPR_END
922
+ if peek(0) == '='
923
+ token.concat getc
924
+ end
925
+ elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
926
+ @lex_state = EXPR_ARG
927
+ else
928
+ @lex_state = EXPR_END
929
+ end
930
+
931
+ if token[0, 1] =~ /[A-Z]/
932
+ return Token(TkCONSTANT, token)
933
+ elsif token[token.size - 1, 1] =~ /[!?]/
934
+ return Token(TkFID, token)
935
+ else
936
+ return Token(TkIDENTIFIER, token)
937
+ end
938
+ end
939
+
940
+ def identify_here_document
941
+ ch = getc
942
+ # if lt = PERCENT_LTYPE[ch]
943
+ if ch == "-"
944
+ ch = getc
945
+ indent = true
946
+ end
947
+ if /['"`]/ =~ ch
948
+ lt = ch
949
+ quoted = ""
950
+ while (c = getc) && c != lt
951
+ quoted.concat c
952
+ end
953
+ else
954
+ lt = '"'
955
+ quoted = ch.dup
956
+ while (c = getc) && c =~ /\w/
957
+ quoted.concat c
958
+ end
959
+ ungetc
960
+ end
961
+
962
+ ltback, @ltype = @ltype, lt
963
+ reserve = []
964
+ while ch = getc
965
+ reserve.push ch
966
+ if ch == "\\"
967
+ reserve.push ch = getc
968
+ elsif ch == "\n"
969
+ break
970
+ end
971
+ end
972
+
973
+ @here_header = false
974
+ doc = ''
975
+ while l = gets
976
+ l = l.sub(/(:?\r)?\n\z/, '')
977
+ if (indent ? l.strip : l) == quoted
978
+ break
979
+ end
980
+ doc << l
981
+ end
982
+
983
+ @here_header = true
984
+ @here_readed.concat reserve
985
+ while ch = reserve.pop
986
+ ungetc ch
987
+ end
988
+
989
+ @ltype = ltback
990
+ @lex_state = EXPR_END
991
+ Token(Ltype2Token[lt], doc)
992
+ end
993
+
994
+ def identify_quotation
995
+ ch = getc
996
+ if lt = PERCENT_LTYPE[ch]
997
+ ch = getc
998
+ elsif ch =~ /\W/
999
+ lt = "\""
1000
+ else
1001
+ raise RDoc::Error, "unknown type of %string #{ch.inspect}"
1002
+ end
1003
+ # if ch !~ /\W/
1004
+ # ungetc
1005
+ # next
1006
+ # end
1007
+ #@ltype = lt
1008
+ @quoted = ch unless @quoted = PERCENT_PAREN[ch]
1009
+ identify_string(lt, @quoted)
1010
+ end
1011
+
1012
+ def identify_number
1013
+ @lex_state = EXPR_END
1014
+
1015
+ num = ''
1016
+
1017
+ if peek(0) == "0" && peek(1) !~ /[.eE]/
1018
+ num << getc
1019
+
1020
+ case peek(0)
1021
+ when /[xX]/
1022
+ ch = getc
1023
+ match = /[0-9a-fA-F_]/
1024
+ when /[bB]/
1025
+ ch = getc
1026
+ match = /[01_]/
1027
+ when /[oO]/
1028
+ ch = getc
1029
+ match = /[0-7_]/
1030
+ when /[dD]/
1031
+ ch = getc
1032
+ match = /[0-9_]/
1033
+ when /[0-7]/
1034
+ match = /[0-7_]/
1035
+ when /[89]/
1036
+ raise RDoc::Error, "Illegal octal digit"
1037
+ else
1038
+ return Token(TkINTEGER, num)
1039
+ end
1040
+
1041
+ num << ch if ch
1042
+
1043
+ len0 = true
1044
+ non_digit = false
1045
+ while ch = getc
1046
+ num << ch
1047
+ if match =~ ch
1048
+ if ch == "_"
1049
+ if non_digit
1050
+ raise RDoc::Error, "trailing `#{ch}' in number"
1051
+ else
1052
+ non_digit = ch
1053
+ end
1054
+ else
1055
+ non_digit = false
1056
+ len0 = false
1057
+ end
1058
+ else
1059
+ ungetc
1060
+ num[-1, 1] = ''
1061
+ if len0
1062
+ raise RDoc::Error, "numeric literal without digits"
1063
+ end
1064
+ if non_digit
1065
+ raise RDoc::Error, "trailing `#{non_digit}' in number"
1066
+ end
1067
+ break
1068
+ end
1069
+ end
1070
+ return Token(TkINTEGER, num)
1071
+ end
1072
+
1073
+ type = TkINTEGER
1074
+ allow_point = true
1075
+ allow_e = true
1076
+ non_digit = false
1077
+ while ch = getc
1078
+ num << ch
1079
+ case ch
1080
+ when /[0-9]/
1081
+ non_digit = false
1082
+ when "_"
1083
+ non_digit = ch
1084
+ when allow_point && "."
1085
+ if non_digit
1086
+ raise RDoc::Error, "trailing `#{non_digit}' in number"
1087
+ end
1088
+ type = TkFLOAT
1089
+ if peek(0) !~ /[0-9]/
1090
+ type = TkINTEGER
1091
+ ungetc
1092
+ num[-1, 1] = ''
1093
+ break
1094
+ end
1095
+ allow_point = false
1096
+ when allow_e && "e", allow_e && "E"
1097
+ if non_digit
1098
+ raise RDoc::Error, "trailing `#{non_digit}' in number"
1099
+ end
1100
+ type = TkFLOAT
1101
+ if peek(0) =~ /[+-]/
1102
+ num << getc
1103
+ end
1104
+ allow_e = false
1105
+ allow_point = false
1106
+ non_digit = ch
1107
+ else
1108
+ if non_digit
1109
+ raise RDoc::Error, "trailing `#{non_digit}' in number"
1110
+ end
1111
+ ungetc
1112
+ num[-1, 1] = ''
1113
+ break
1114
+ end
1115
+ end
1116
+
1117
+ Token(type, num)
1118
+ end
1119
+
1120
+ def identify_string(ltype, quoted = ltype)
1121
+ @ltype = ltype
1122
+ @quoted = quoted
1123
+ str = @ltype.dup
1124
+
1125
+ subtype = nil
1126
+ begin
1127
+ nest = 0
1128
+
1129
+ while ch = getc
1130
+ str << ch
1131
+
1132
+ if @quoted == ch and nest == 0
1133
+ break
1134
+ elsif @ltype != "'" && @ltype != "]" && @ltype != ":" and ch == "#"
1135
+ ch = getc
1136
+ subtype = true
1137
+ if ch == "{" then
1138
+ str << ch << skip_inner_expression
1139
+ else
1140
+ ungetc
1141
+ end
1142
+ elsif ch == '\\' and @ltype == "'" #'
1143
+ case ch = getc
1144
+ when "\\", "\n", "'"
1145
+ else
1146
+ ungetc
1147
+ end
1148
+ elsif ch == '\\' #'
1149
+ str << read_escape
1150
+ end
1151
+
1152
+ if PERCENT_PAREN.values.include?(@quoted)
1153
+ if PERCENT_PAREN[ch] == @quoted
1154
+ nest += 1
1155
+ elsif ch == @quoted
1156
+ nest -= 1
1157
+ end
1158
+ end
1159
+ end
1160
+
1161
+ if @ltype == "/"
1162
+ if peek(0) =~ /i|m|x|o|e|s|u|n/
1163
+ getc
1164
+ end
1165
+ end
1166
+
1167
+ if subtype
1168
+ Token(DLtype2Token[ltype], str)
1169
+ else
1170
+ Token(Ltype2Token[ltype], str)
1171
+ end
1172
+ ensure
1173
+ @ltype = nil
1174
+ @quoted = nil
1175
+ @lex_state = EXPR_END
1176
+ end
1177
+ end
1178
+
1179
+ def skip_inner_expression
1180
+ res = ""
1181
+ nest = 0
1182
+ while (ch = getc)
1183
+ res << ch
1184
+ if ch == '}'
1185
+ break if nest.zero?
1186
+ nest -= 1
1187
+ elsif ch == '{'
1188
+ nest += 1
1189
+ end
1190
+ end
1191
+ res
1192
+ end
1193
+
1194
+ def identify_comment
1195
+ @ltype = "#"
1196
+
1197
+ comment = '#'
1198
+
1199
+ while ch = getc
1200
+ # if ch == "\\" #"
1201
+ # read_escape
1202
+ # end
1203
+ if ch == "\n"
1204
+ @ltype = nil
1205
+ ungetc
1206
+ break
1207
+ end
1208
+
1209
+ comment << ch
1210
+ end
1211
+
1212
+ return Token(TkCOMMENT, comment)
1213
+ end
1214
+
1215
+ def read_escape
1216
+ escape = ''
1217
+ ch = getc
1218
+ escape << ch
1219
+
1220
+ case ch
1221
+ when "\n", "\r", "\f"
1222
+ when "\\", "n", "t", "r", "f", "v", "a", "e", "b", "s" #"
1223
+ when /[0-7]/
1224
+ ungetc ch
1225
+ 3.times do
1226
+ ch = getc
1227
+ escape << ch
1228
+ case ch
1229
+ when /[0-7]/
1230
+ when nil
1231
+ break
1232
+ else
1233
+ ungetc
1234
+ break
1235
+ end
1236
+ end
1237
+
1238
+ when "x"
1239
+ 2.times do
1240
+ ch = getc
1241
+ escape << ch
1242
+ case ch
1243
+ when /[0-9a-fA-F]/
1244
+ when nil
1245
+ break
1246
+ else
1247
+ ungetc
1248
+ break
1249
+ end
1250
+ end
1251
+
1252
+ when "M"
1253
+ ch = getc
1254
+ escape << ch
1255
+ if ch != '-'
1256
+ ungetc
1257
+ else
1258
+ ch = getc
1259
+ escape << ch
1260
+ if ch == "\\" #"
1261
+ escape << read_escape
1262
+ end
1263
+ end
1264
+
1265
+ when "C", "c" #, "^"
1266
+ if ch == "C" and (ch = getc) != "-"
1267
+ escape << ch
1268
+ ungetc
1269
+ elsif (ch = getc) == "\\" #"
1270
+ escape << ch << read_escape
1271
+ end
1272
+ else
1273
+ # other characters
1274
+ end
1275
+
1276
+ escape
1277
+ end
1278
+
1279
+ # :startdoc:
1280
+
1281
+ end
1282
+
1283
+ #RDoc::RubyLex.debug_level = 1
1284
+