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.
- data.tar.gz.sig +0 -0
- data/.autotest +3 -1
- data/History.txt +68 -0
- data/LICENSE.txt +57 -0
- data/Manifest.txt +37 -19
- data/README.txt +2 -12
- data/Rakefile +12 -12
- data/bin/rdoc +4 -4
- data/lib/rdoc.rb +32 -9
- data/lib/rdoc/alias.rb +2 -2
- data/lib/rdoc/any_method.rb +108 -16
- data/lib/rdoc/attr.rb +87 -1
- data/lib/rdoc/class_module.rb +131 -5
- data/lib/rdoc/code_object.rb +28 -5
- data/lib/rdoc/constant.rb +22 -0
- data/lib/rdoc/context.rb +80 -37
- data/lib/rdoc/gauntlet.rb +48 -0
- data/lib/rdoc/generator/darkfish.rb +25 -23
- data/lib/rdoc/generator/markup.rb +6 -29
- data/lib/rdoc/generator/ri.rb +39 -189
- data/lib/rdoc/generator/template/darkfish/classpage.rhtml +17 -1
- data/lib/rdoc/generator/template/darkfish/filepage.rhtml +10 -0
- data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
- data/lib/rdoc/generator/template/darkfish/index.rhtml +2 -2
- data/lib/rdoc/generator/template/darkfish/rdoc.css +38 -33
- data/lib/rdoc/include.rb +22 -0
- data/lib/rdoc/markup.rb +10 -262
- data/lib/rdoc/markup/attribute_manager.rb +57 -50
- data/lib/rdoc/markup/blank_line.rb +19 -0
- data/lib/rdoc/markup/document.rb +72 -0
- data/lib/rdoc/markup/formatter.rb +118 -0
- data/lib/rdoc/markup/formatter_test_case.rb +341 -0
- data/lib/rdoc/markup/heading.rb +17 -0
- data/lib/rdoc/markup/inline.rb +6 -5
- data/lib/rdoc/markup/list.rb +78 -0
- data/lib/rdoc/markup/list_item.rb +83 -0
- data/lib/rdoc/markup/paragraph.rb +66 -0
- data/lib/rdoc/markup/parser.rb +528 -0
- data/lib/rdoc/markup/rule.rb +17 -0
- data/lib/rdoc/markup/to_ansi.rb +72 -0
- data/lib/rdoc/markup/to_bs.rb +74 -0
- data/lib/rdoc/markup/to_html.rb +106 -172
- data/lib/rdoc/markup/to_html_crossref.rb +10 -4
- data/lib/rdoc/markup/to_rdoc.rb +243 -0
- data/lib/rdoc/markup/to_test.rb +27 -16
- data/lib/rdoc/markup/verbatim.rb +42 -0
- data/lib/rdoc/normal_class.rb +38 -1
- data/lib/rdoc/normal_module.rb +38 -8
- data/lib/rdoc/options.rb +39 -151
- data/lib/rdoc/parser.rb +36 -18
- data/lib/rdoc/parser/c.rb +102 -109
- data/lib/rdoc/parser/ruby.rb +359 -1662
- data/lib/rdoc/parser/ruby_tools.rb +157 -0
- data/lib/rdoc/parser/simple.rb +0 -2
- data/lib/rdoc/rdoc.rb +142 -82
- data/lib/rdoc/ri.rb +10 -0
- data/lib/rdoc/ri/driver.rb +674 -444
- data/lib/rdoc/ri/formatter.rb +2 -651
- data/lib/rdoc/ri/paths.rb +70 -45
- data/lib/rdoc/ri/store.rb +248 -0
- data/lib/rdoc/ruby_lex.rb +1284 -0
- data/lib/rdoc/ruby_token.rb +416 -0
- data/lib/rdoc/single_class.rb +5 -0
- data/lib/rdoc/stats.rb +152 -83
- data/lib/rdoc/task.rb +27 -49
- data/lib/rdoc/text.rb +130 -0
- data/lib/rdoc/tokenstream.rb +28 -9
- data/lib/rdoc/top_level.rb +49 -43
- data/test/hidden.zip.txt +1 -0
- data/test/test_attribute_manager.rb +9 -16
- data/test/test_rdoc_any_method.rb +23 -0
- data/test/test_rdoc_attr.rb +40 -0
- data/test/test_rdoc_class_module.rb +100 -0
- data/test/test_rdoc_code_object.rb +18 -2
- data/test/test_rdoc_context.rb +41 -0
- data/test/test_rdoc_generator_ri.rb +56 -0
- data/test/test_rdoc_markup.rb +21 -610
- data/test/test_rdoc_markup_attribute_manager.rb +14 -17
- data/test/test_rdoc_markup_document.rb +51 -0
- data/test/test_rdoc_markup_paragraph.rb +27 -0
- data/test/test_rdoc_markup_parser.rb +1327 -0
- data/test/test_rdoc_markup_to_ansi.rb +426 -0
- data/test/test_rdoc_markup_to_bs.rb +443 -0
- data/test/test_rdoc_markup_to_html.rb +183 -18
- data/test/test_rdoc_markup_to_html_crossref.rb +1 -3
- data/test/test_rdoc_markup_to_rdoc.rb +426 -0
- data/test/test_rdoc_normal_class.rb +17 -0
- data/test/test_rdoc_normal_module.rb +6 -6
- data/test/test_rdoc_options.rb +41 -0
- data/test/test_rdoc_parser.rb +66 -13
- data/test/test_rdoc_parser_c.rb +93 -38
- data/test/test_rdoc_parser_perl.rb +2 -3
- data/test/test_rdoc_parser_ruby.rb +291 -28
- data/test/test_rdoc_parser_simple.rb +48 -0
- data/test/test_rdoc_rdoc.rb +66 -0
- data/test/test_rdoc_ri_driver.rb +752 -38
- data/test/test_rdoc_ri_paths.rb +39 -0
- data/test/test_rdoc_ri_store.rb +309 -0
- data/test/test_rdoc_text.rb +157 -0
- data/test/test_rdoc_top_level.rb +35 -9
- data/test/xref_data.rb +9 -1
- data/test/xref_test_case.rb +8 -3
- metadata +110 -38
- metadata.gz.sig +0 -0
- data/lib/rdoc/cache.rb +0 -41
- data/lib/rdoc/diagram.rb +0 -340
- data/lib/rdoc/dot.rb +0 -249
- data/lib/rdoc/markup/fragments.rb +0 -377
- data/lib/rdoc/markup/lines.rb +0 -156
- data/lib/rdoc/markup/to_flow.rb +0 -211
- data/lib/rdoc/markup/to_latex.rb +0 -328
- data/lib/rdoc/markup/to_texinfo.rb +0 -73
- data/lib/rdoc/ri/cache.rb +0 -187
- data/lib/rdoc/ri/descriptions.rb +0 -156
- data/lib/rdoc/ri/display.rb +0 -340
- data/lib/rdoc/ri/reader.rb +0 -106
- data/lib/rdoc/ri/util.rb +0 -79
- data/lib/rdoc/ri/writer.rb +0 -68
- data/test/test_rdoc_ri_attribute_formatter.rb +0 -44
- data/test/test_rdoc_ri_default_display.rb +0 -302
- data/test/test_rdoc_ri_formatter.rb +0 -320
- data/test/test_rdoc_ri_html_formatter.rb +0 -141
- data/test/test_rdoc_ri_overstrike_formatter.rb +0 -71
data/lib/rdoc/ri/paths.rb
CHANGED
@@ -1,45 +1,63 @@
|
|
1
1
|
require 'rdoc/ri'
|
2
2
|
|
3
3
|
##
|
4
|
-
#
|
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
|
-
|
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
|
-
|
44
|
+
yield SYSDIR, :system if system
|
45
|
+
yield SITEDIR, :site if site
|
46
|
+
yield HOMEDIR, :home if home
|
30
47
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
|
48
|
+
gemdirs.each do |dir|
|
49
|
+
yield dir, :gem
|
50
|
+
end if gems
|
35
51
|
|
36
|
-
|
37
|
-
HOMEDIR = File.join(homedir, ".rdoc")
|
38
|
-
else
|
39
|
-
HOMEDIR = nil
|
52
|
+
nil
|
40
53
|
end
|
41
54
|
|
42
|
-
|
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
|
-
|
84
|
+
@gemdirs = ri_paths.map { |k,v| v.last }.sort
|
67
85
|
rescue LoadError
|
68
|
-
|
86
|
+
@gemdirs = []
|
69
87
|
end
|
70
88
|
|
71
|
-
|
72
|
-
#
|
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
|
-
|
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
|
-
|
80
|
-
#
|
81
|
-
#
|
101
|
+
##
|
102
|
+
# Returns selected documentation directories including nonexistent
|
103
|
+
# directories.
|
104
|
+
#
|
105
|
+
# See also ::each
|
82
106
|
|
83
|
-
def self.raw_path(
|
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
|
-
|
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
|
+
|