yard 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/bin/yardoc +30 -7
- data/lib/code_object.rb +16 -19
- data/lib/extra.rb +8 -0
- data/lib/formatter.rb +30 -18
- data/lib/handlers/attribute_handler.rb +9 -4
- data/lib/handlers/class_handler.rb +3 -2
- data/lib/handlers/constant_handler.rb +1 -1
- data/lib/handlers/exception_handler.rb +1 -1
- data/lib/handlers/method_handler.rb +2 -1
- data/lib/handlers/mixin_handler.rb +7 -1
- data/lib/handlers/module_handler.rb +1 -1
- data/lib/handlers/yield_handler.rb +24 -22
- data/lib/logger.rb +19 -0
- data/lib/ruby_lex.rb +1116 -1113
- data/lib/source_parser.rb +12 -5
- data/lib/tag_library.rb +24 -11
- data/lib/yard.rb +6 -1
- data/templates/default/html/_fulldoc.erb +64 -0
- data/templates/default/html/class.erb +226 -0
- data/templates/default/html/method.erb +20 -0
- data/templates/default/html/module.erb +126 -0
- metadata +66 -44
- data/templates/html_formatter.erb +0 -455
data/bin/yardoc
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
#!/usr/bin/ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
require File.dirname(__FILE__) + '/../lib/yard'
|
3
3
|
include YARD
|
4
4
|
|
5
5
|
if ARGV[0] == "-h"
|
6
|
-
puts "yardoc
|
6
|
+
puts "yardoc #{VERSION}"
|
7
7
|
return
|
8
8
|
end
|
9
9
|
|
@@ -18,6 +18,15 @@ ac.puts <<-eof
|
|
18
18
|
<body>
|
19
19
|
<h3>All Classes</h3>
|
20
20
|
eof
|
21
|
+
am = File.open("doc/all-modules.html", "w")
|
22
|
+
am.puts <<-eof
|
23
|
+
<html>
|
24
|
+
<head>
|
25
|
+
<base target="main" />
|
26
|
+
</head>
|
27
|
+
<body>
|
28
|
+
<h3>All Modules</h3>
|
29
|
+
eof
|
21
30
|
meths = []
|
22
31
|
Namespace.all.sort.each do |path|
|
23
32
|
object = Namespace.at(path)
|
@@ -25,12 +34,25 @@ Namespace.all.sort.each do |path|
|
|
25
34
|
meths << [object.name, object]
|
26
35
|
end
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
indexfile = nil
|
38
|
+
|
39
|
+
case object
|
40
|
+
when ClassObject
|
41
|
+
indexfile = ac
|
42
|
+
when ModuleObject
|
43
|
+
indexfile = am
|
44
|
+
else
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
indexfile.puts "<a href='" + path.gsub("::","_") + ".html'>" + path + "</a><br />"
|
49
|
+
puts "Generating " + (docfile = "doc/#{path.gsub('::','_')}.html") + "..."
|
50
|
+
File.open(docfile, "w") {|f| f.write(object.to_s) }
|
31
51
|
end
|
32
52
|
ac.puts "</body></html>"
|
33
53
|
ac.close
|
54
|
+
am.puts "</body></html>"
|
55
|
+
am.close
|
34
56
|
|
35
57
|
File.open("doc/all-methods.html", "w") do |f|
|
36
58
|
f.puts <<-eof
|
@@ -40,7 +62,7 @@ File.open("doc/all-methods.html", "w") do |f|
|
|
40
62
|
</head>
|
41
63
|
<body>
|
42
64
|
<h3>All Methods</h3>
|
43
|
-
eof
|
65
|
+
eof
|
44
66
|
meths.sort {|a,b| a.first <=> b.first }.each do |name, object|
|
45
67
|
f.puts "<a href='" + object.parent.path.gsub("::", "_") + ".html##{object.scope}_method-#{name}'>#{name}</a><br />"
|
46
68
|
end
|
@@ -62,8 +84,9 @@ File.open("doc/index.html", "w") do |f|
|
|
62
84
|
<title>Ruby Classes</title>
|
63
85
|
</head>
|
64
86
|
<frameset cols="250,*">
|
65
|
-
<frameset rows="
|
87
|
+
<frameset rows="40%,40%,20%">
|
66
88
|
<frame src="all-classes.html">
|
89
|
+
<frame src="all-modules.html">
|
67
90
|
<frame src="all-methods.html">
|
68
91
|
</frameset>
|
69
92
|
<frame name="main" src="#{main_page}">
|
data/lib/code_object.rb
CHANGED
@@ -8,6 +8,9 @@ module YARD #:nodoc:
|
|
8
8
|
#
|
9
9
|
# @author Loren Segal
|
10
10
|
class CodeObject
|
11
|
+
SCOPES = [:class, :instance]
|
12
|
+
VISIBILITIES = [:private, :protected, :public]
|
13
|
+
|
11
14
|
attr_reader :source, :full_source, :file, :line, :docstring, :attributes
|
12
15
|
|
13
16
|
attr_reader :name, :type
|
@@ -42,10 +45,6 @@ module YARD #:nodoc:
|
|
42
45
|
yield(self) if block_given?
|
43
46
|
end
|
44
47
|
|
45
|
-
def to_s
|
46
|
-
"#{visibility} #{type} #{path}"
|
47
|
-
end
|
48
|
-
|
49
48
|
##
|
50
49
|
# Attaches source code to a code object with an optional file location
|
51
50
|
#
|
@@ -132,7 +131,7 @@ module YARD #:nodoc:
|
|
132
131
|
#
|
133
132
|
#
|
134
133
|
def path
|
135
|
-
[(parent.path if parent && parent.type != :root), name].join(scope == :instance ? "#" : "::").gsub(/^::/, '')
|
134
|
+
[(parent.path if parent && parent.type != :root), name].join(scope == :instance ? "#" : "::").gsub(/^::/, '').trim
|
136
135
|
end
|
137
136
|
|
138
137
|
##
|
@@ -170,16 +169,7 @@ module YARD #:nodoc:
|
|
170
169
|
name = name.to_s
|
171
170
|
@tags.any? {|tag| tag.tag_name == name }
|
172
171
|
end
|
173
|
-
|
174
|
-
##
|
175
|
-
# Returns a code object formatted as a given type, defaults to html.
|
176
|
-
#
|
177
|
-
# @param [Symbol] format the output format to generate
|
178
|
-
# @return [String] the code object formatted by the specified +format+
|
179
|
-
def format(type = :html)
|
180
|
-
Formatter.new.format(self, type)
|
181
|
-
end
|
182
|
-
|
172
|
+
|
183
173
|
private
|
184
174
|
##
|
185
175
|
# Parses out comments split by newlines into a new code object
|
@@ -231,6 +221,7 @@ module YARD #:nodoc:
|
|
231
221
|
class CodeObjectWithMethods < CodeObject
|
232
222
|
def initialize(name, type, parent = nil, comments = nil)
|
233
223
|
super(name, type, :public, :class, parent, comments) do |obj|
|
224
|
+
obj[:attributes] = {}
|
234
225
|
obj[:instance_methods] = {}
|
235
226
|
obj[:class_methods] = {}
|
236
227
|
obj[:constants] = {}
|
@@ -265,6 +256,11 @@ module YARD #:nodoc:
|
|
265
256
|
yield(obj) if block_given?
|
266
257
|
end
|
267
258
|
end
|
259
|
+
|
260
|
+
def superclasses
|
261
|
+
#STDERR.puts "Warning: someone expected module #{path} to respond to #superclasses"
|
262
|
+
[]
|
263
|
+
end
|
268
264
|
end
|
269
265
|
|
270
266
|
class ClassObject < CodeObjectWithMethods
|
@@ -272,7 +268,6 @@ module YARD #:nodoc:
|
|
272
268
|
|
273
269
|
def initialize(name, superclass = BASE_OBJECT, *args)
|
274
270
|
super(name, :class, *args) do |obj|
|
275
|
-
obj[:attributes] = {}
|
276
271
|
obj[:superclass] = superclass
|
277
272
|
yield(obj) if block_given?
|
278
273
|
end
|
@@ -292,8 +287,9 @@ module YARD #:nodoc:
|
|
292
287
|
|
293
288
|
def superclasses
|
294
289
|
superobject = Namespace.find_from_path(path, superclass)
|
295
|
-
return [
|
296
|
-
[
|
290
|
+
return ["Object"] unless superobject
|
291
|
+
return [] if path == superobject.path
|
292
|
+
[superobject.path, *superobject.superclasses]
|
297
293
|
end
|
298
294
|
|
299
295
|
def inheritance_tree
|
@@ -308,7 +304,8 @@ module YARD #:nodoc:
|
|
308
304
|
# @param [CodeObjectWithMethods] parent the object that holds this method
|
309
305
|
def initialize(name, visibility, scope, parent, comments = nil)
|
310
306
|
super(name, :method, visibility, scope, parent, comments) do |obj|
|
311
|
-
parent["#{scope}_methods".to_sym]
|
307
|
+
pmethods = parent["#{scope}_methods".to_sym]
|
308
|
+
pmethods.update(name.to_s => obj) if pmethods
|
312
309
|
yield(obj) if block_given?
|
313
310
|
end
|
314
311
|
end
|
data/lib/extra.rb
ADDED
data/lib/formatter.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'erubis'
|
2
3
|
require 'rdoc/markup/simple_markup'
|
3
4
|
require 'rdoc/markup/simple_markup/to_html'
|
4
5
|
|
@@ -12,21 +13,17 @@ module YARD
|
|
12
13
|
# @author Loren Segal
|
13
14
|
# @version 1.0
|
14
15
|
class Formatter
|
15
|
-
OUTPUT_FORMATS = [ :html, :xhtml, :xml ]
|
16
|
-
|
17
16
|
##
|
18
17
|
# Formats an object as a specified output format. Default is +:html+.
|
19
18
|
#
|
20
|
-
# @param
|
21
|
-
#
|
22
|
-
#
|
19
|
+
# @param format the output format to generate documentation in.
|
20
|
+
# Defaults to +:html+, which is a synonym for <tt>:xhtml</tt>
|
21
|
+
# @param template the template sub directory to use, default is <tt>:default</tt>
|
23
22
|
# @see OUTPUT_FORMATS
|
24
|
-
def format(object, format
|
23
|
+
def format(object, format, template)
|
25
24
|
object = Namespace.at(object) if object.is_a? String
|
26
|
-
|
27
|
-
|
28
|
-
@object = object
|
29
|
-
ERB.new(IO.read(erb), nil, ">").result(binding)
|
25
|
+
@object, @format, @template = object, format, template
|
26
|
+
render(@object.type)
|
30
27
|
end
|
31
28
|
|
32
29
|
##
|
@@ -34,9 +31,21 @@ module YARD
|
|
34
31
|
def template_directory
|
35
32
|
File.join(File.dirname(__FILE__), '..', 'templates')
|
36
33
|
end
|
34
|
+
|
35
|
+
def render(type, format = @format, template = @template)
|
36
|
+
formatter = self
|
37
|
+
_binding = @object ? @object.instance_eval("binding") : binding
|
38
|
+
filename = File.join(template_directory, template.to_s, format.to_s, "#{type}.erb")
|
39
|
+
Erubis::Eruby.new("<% extend #{format.to_s.capitalize}Formatter %>\n" +
|
40
|
+
IO.read(filename), :trim => true).result(_binding)
|
41
|
+
rescue => e
|
42
|
+
STDERR.puts "Could not render template #{filename}: #{e.message}"
|
43
|
+
STDERR.puts e.backtrace[0, 5].map {|x| "\t#{x}" }
|
44
|
+
STDERR.puts
|
45
|
+
end
|
37
46
|
end
|
38
47
|
|
39
|
-
|
48
|
+
module HtmlFormatter
|
40
49
|
def link_to_path(name, from_path = nil, label = nil)
|
41
50
|
return "<a href='#instance_method-#{name[1..-1]}'>#{label || name}</a>" if name =~ /^\#/ && from_path.nil?
|
42
51
|
|
@@ -48,7 +57,7 @@ module YARD
|
|
48
57
|
|
49
58
|
label = name if label.nil?
|
50
59
|
if obj
|
51
|
-
file = obj.parent.path.gsub("::","_") + ".html"
|
60
|
+
file = (obj.parent || obj).path.gsub("::","_") + ".html"
|
52
61
|
case obj
|
53
62
|
when ConstantObject
|
54
63
|
"<a href='#{file}#const-#{obj.name}'>#{label}</a>"
|
@@ -69,10 +78,13 @@ module YARD
|
|
69
78
|
end
|
70
79
|
|
71
80
|
def resolve_links(text, path)
|
72
|
-
|
73
|
-
while t =~ re
|
74
|
-
t.sub!(re, "<tt>" + link_to_path($1, path) + "</tt>")
|
75
|
-
end
|
76
|
-
t
|
81
|
+
text.gsub(/\{(.+?)\}/) {|match| "<tt>" + link_to_path(match, path) + "</tt>" }
|
77
82
|
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class CodeObject
|
86
|
+
def to_s(format = :html, template = :default)
|
87
|
+
Formatter.new.format(self, format, template)
|
88
|
+
end
|
89
|
+
end
|
78
90
|
end
|
@@ -2,9 +2,14 @@ class YARD::AttributeHandler < YARD::CodeObjectHandler
|
|
2
2
|
handles /\Aattr(_(reader|writer|accessor))?\b/
|
3
3
|
|
4
4
|
def process
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
begin
|
6
|
+
attr_type = statement.tokens.first.text.to_sym
|
7
|
+
symbols = eval("[" + statement.tokens[1..-1].to_s + "]")
|
8
|
+
read, write = true, false
|
9
|
+
rescue SyntaxError
|
10
|
+
Logger.warning "in AttributeHandler: Undocumentable attribute statement: '#{statement.tokens.to_s}'"
|
11
|
+
return
|
12
|
+
end
|
8
13
|
|
9
14
|
# Change read/write based on attr_reader/writer/accessor
|
10
15
|
case attr_type
|
@@ -22,7 +27,7 @@ class YARD::AttributeHandler < YARD::CodeObjectHandler
|
|
22
27
|
# Add all attributes
|
23
28
|
symbols.each do |name|
|
24
29
|
name = name.to_s
|
25
|
-
object[:attributes].update(name.to_s => { :read => read, :write => write })
|
30
|
+
object[:attributes].update(name.to_s => { :read => read, :write => write }) if object.type == :class
|
26
31
|
|
27
32
|
# Show their methods as well
|
28
33
|
[name, "#{name}="].each do |method|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class YARD::ClassHandler < YARD::CodeObjectHandler
|
2
|
-
handles RubyToken::TkCLASS
|
2
|
+
handles YARD::RubyToken::TkCLASS
|
3
3
|
|
4
4
|
def process
|
5
5
|
words = statement.tokens.to_s.strip.split(/\s+/)
|
@@ -22,7 +22,8 @@ class YARD::ClassHandler < YARD::CodeObjectHandler
|
|
22
22
|
current_namespace.attributes[:scope], current_visibility = scope, vis
|
23
23
|
else
|
24
24
|
class_name = move_to_namespace(class_name)
|
25
|
-
class_obj =
|
25
|
+
class_obj = Namespace.find_from_path(object, class_name)
|
26
|
+
class_obj ||= YARD::ClassObject.new(class_name, superclass, object, statement.comments)
|
26
27
|
enter_namespace(class_obj) { parse_block }
|
27
28
|
end
|
28
29
|
end
|
@@ -7,7 +7,7 @@ class YARD::ExceptionHandler < YARD::CodeObjectHandler
|
|
7
7
|
break index if token.class == RubyToken::TkIDENTIFIER && token.text == 'raise'
|
8
8
|
end
|
9
9
|
if from.is_a? Fixnum
|
10
|
-
exception_class = tokens[(from+1)..-1].to_s[/^\
|
10
|
+
exception_class = tokens[(from+1)..-1].to_s[/^\W+(\w+)/, 1]
|
11
11
|
# RuntimeError for Strings or no parameter
|
12
12
|
exception_class = "RuntimeError" if exception_class =~ /^\"/ || exception_class.nil?
|
13
13
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class YARD::MethodHandler < YARD::CodeObjectHandler
|
2
|
-
handles RubyToken::TkDEF
|
2
|
+
handles YARD::RubyToken::TkDEF
|
3
3
|
|
4
4
|
def process
|
5
|
+
return unless object.is_a? YARD::CodeObjectWithMethods
|
5
6
|
stmt_nospace = statement.tokens.reject {|t| t.is_a? RubyToken::TkSPACE }
|
6
7
|
method_name, method_scope = stmt_nospace[1].text, current_scope
|
7
8
|
holding_object = object
|
@@ -3,7 +3,13 @@ class YARD::MixinHandler < YARD::CodeObjectHandler
|
|
3
3
|
|
4
4
|
def process
|
5
5
|
return unless object.is_a? YARD::CodeObjectWithMethods
|
6
|
-
|
6
|
+
begin
|
7
|
+
object.mixins.push eval("[ " + statement.tokens[1..-1].to_s + " ]").to_s
|
8
|
+
rescue NameError
|
9
|
+
object.mixins.push statement.tokens[1..-1].to_s
|
10
|
+
end
|
11
|
+
object.mixins.map! {|mixin| mixin.trim }
|
12
|
+
object.mixins.flatten!
|
7
13
|
object.mixins.uniq!
|
8
14
|
end
|
9
15
|
end
|
@@ -1,29 +1,31 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module YARD
|
2
|
+
class YieldHandler < CodeObjectHandler
|
3
|
+
handles 'yield'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
if from.is_a? Fixnum
|
10
|
-
params = []
|
11
|
-
(from+1).step(tokens.size-1, 2) do |index|
|
12
|
-
# FIXME: This won't work if the yield has a method call or complex constant name (A::B)
|
13
|
-
params << tokens[index].text
|
14
|
-
break unless tokens[index+1].is_a? RubyToken::TkCOMMA
|
5
|
+
def process
|
6
|
+
tokens = statement.tokens.reject {|tk| [RubyToken::TkSPACE, RubyToken::TkLPAREN].include? tk.class }
|
7
|
+
from = tokens.each_with_index do |token, index|
|
8
|
+
break index if token.class == RubyToken::TkYIELD
|
15
9
|
end
|
10
|
+
if from.is_a? Fixnum
|
11
|
+
params = []
|
12
|
+
(from+1).step(tokens.size-1, 2) do |index|
|
13
|
+
# FIXME: This won't work if the yield has a method call or complex constant name (A::B)
|
14
|
+
params << tokens[index].text
|
15
|
+
break unless tokens[index+1].is_a? RubyToken::TkCOMMA
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
# Only add the tags if none were added at all
|
19
|
+
if object.tags("yieldparam").empty? && object.tags("yield").empty?
|
20
|
+
params.each do |param|
|
21
|
+
# TODO: We can technically introspect any constant to find out parameter types,
|
22
|
+
# not just self.
|
23
|
+
# If parameter is self, we have a chance to get some extra information
|
24
|
+
if param == "self"
|
25
|
+
param = "[#{object.parent.path}] _self the object that yields the value (self)"
|
26
|
+
end
|
27
|
+
object.tags << YARD::TagLibrary.yieldparam_tag(param)
|
25
28
|
end
|
26
|
-
object.tags << YARD::TagLibrary.yieldparam_tag(param)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/logger.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Logger
|
2
|
+
class << self
|
3
|
+
attr_accessor :notices, :warnings, :errors
|
4
|
+
@notices, @warnings, @errors = true, true, true
|
5
|
+
|
6
|
+
def notice
|
7
|
+
puts "Notice: #{msg}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def warning(msg)
|
11
|
+
puts "Warning: #{msg}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def error(msg)
|
15
|
+
puts "Error: #{msg}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/lib/ruby_lex.rb
CHANGED
@@ -1,1318 +1,1321 @@
|
|
1
1
|
require "e2mmap"
|
2
2
|
require "irb/slex"
|
3
3
|
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
module YARD
|
5
|
+
module RubyToken
|
6
|
+
EXPR_BEG = :EXPR_BEG
|
7
|
+
EXPR_MID = :EXPR_MID
|
8
|
+
EXPR_END = :EXPR_END
|
9
|
+
EXPR_ARG = :EXPR_ARG
|
10
|
+
EXPR_FNAME = :EXPR_FNAME
|
11
|
+
EXPR_DOT = :EXPR_DOT
|
12
|
+
EXPR_CLASS = :EXPR_CLASS
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
class Token
|
15
|
+
NO_TEXT = "??".freeze
|
16
|
+
attr :text
|
17
|
+
|
18
|
+
def initialize(line_no, char_no)
|
19
|
+
@line_no = line_no
|
20
|
+
@char_no = char_no
|
21
|
+
@text = NO_TEXT
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
# Because we're used in contexts that expect to return a token,
|
25
|
+
# we set the text string and then return ourselves
|
26
|
+
def set_text(text)
|
27
|
+
@text = text
|
28
|
+
self
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
attr_reader :line_no, :char_no, :text
|
32
|
+
attr_accessor :lex_state
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
class TkNode < Token
|
36
|
+
attr :node
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
class TkId < Token
|
40
|
+
def initialize(line_no, char_no, name)
|
41
|
+
super(line_no, char_no)
|
42
|
+
@name = name
|
43
|
+
end
|
44
|
+
attr :name
|
42
45
|
end
|
43
|
-
attr :name
|
44
|
-
end
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
class TkKW < TkId
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
class TkVal < Token
|
51
|
+
def initialize(line_no, char_no, value = nil)
|
52
|
+
super(line_no, char_no)
|
53
|
+
set_text(value)
|
54
|
+
end
|
53
55
|
end
|
54
|
-
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
class TkOp < Token
|
58
|
+
def name
|
59
|
+
self.class.op_name
|
60
|
+
end
|
59
61
|
end
|
60
|
-
end
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
class TkOPASGN < TkOp
|
64
|
+
def initialize(line_no, char_no, op)
|
65
|
+
super(line_no, char_no)
|
66
|
+
op = TkReading2Token[op] unless op.kind_of?(Symbol)
|
67
|
+
@op = op
|
68
|
+
end
|
69
|
+
attr :op
|
67
70
|
end
|
68
|
-
attr :op
|
69
|
-
end
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
class TkUnknownChar < Token
|
73
|
+
def initialize(line_no, char_no, id)
|
74
|
+
super(line_no, char_no)
|
75
|
+
@name = char_no.chr
|
76
|
+
end
|
77
|
+
attr :name
|
75
78
|
end
|
76
|
-
attr :name
|
77
|
-
end
|
78
79
|
|
79
|
-
|
80
|
-
|
80
|
+
class TkError < Token
|
81
|
+
end
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
def set_token_position(line, char)
|
84
|
+
@prev_line_no = line
|
85
|
+
@prev_char_no = char
|
86
|
+
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
88
|
+
def Token(token, value = nil)
|
89
|
+
tk = nil
|
90
|
+
case token
|
91
|
+
when String, Symbol
|
92
|
+
source = token.kind_of?(String) ? TkReading2Token : TkSymbol2Token
|
93
|
+
if (tk = source[token]).nil?
|
94
|
+
IRB.fail TkReading2TokenNoKey, token
|
95
|
+
end
|
96
|
+
tk = Token(tk[0], value)
|
97
|
+
else
|
98
|
+
tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
|
99
|
+
token.new(@prev_line_no, @prev_char_no)
|
100
|
+
else
|
101
|
+
token.new(@prev_line_no, @prev_char_no, value)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
tk
|
102
105
|
end
|
103
|
-
tk
|
104
|
-
end
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
107
|
+
TokenDefinitions = [
|
108
|
+
[:TkCLASS, TkKW, "class", EXPR_CLASS],
|
109
|
+
[:TkMODULE, TkKW, "module", EXPR_BEG],
|
110
|
+
[:TkDEF, TkKW, "def", EXPR_FNAME],
|
111
|
+
[:TkUNDEF, TkKW, "undef", EXPR_FNAME],
|
112
|
+
[:TkBEGIN, TkKW, "begin", EXPR_BEG],
|
113
|
+
[:TkRESCUE, TkKW, "rescue", EXPR_MID],
|
114
|
+
[:TkENSURE, TkKW, "ensure", EXPR_BEG],
|
115
|
+
[:TkEND, TkKW, "end", EXPR_END],
|
116
|
+
[:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD],
|
117
|
+
[:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD],
|
118
|
+
[:TkTHEN, TkKW, "then", EXPR_BEG],
|
119
|
+
[:TkELSIF, TkKW, "elsif", EXPR_BEG],
|
120
|
+
[:TkELSE, TkKW, "else", EXPR_BEG],
|
121
|
+
[:TkCASE, TkKW, "case", EXPR_BEG],
|
122
|
+
[:TkWHEN, TkKW, "when", EXPR_BEG],
|
123
|
+
[:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD],
|
124
|
+
[:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD],
|
125
|
+
[:TkFOR, TkKW, "for", EXPR_BEG],
|
126
|
+
[:TkBREAK, TkKW, "break", EXPR_END],
|
127
|
+
[:TkNEXT, TkKW, "next", EXPR_END],
|
128
|
+
[:TkREDO, TkKW, "redo", EXPR_END],
|
129
|
+
[:TkRETRY, TkKW, "retry", EXPR_END],
|
130
|
+
[:TkIN, TkKW, "in", EXPR_BEG],
|
131
|
+
[:TkDO, TkKW, "do", EXPR_BEG],
|
132
|
+
[:TkRETURN, TkKW, "return", EXPR_MID],
|
133
|
+
[:TkYIELD, TkKW, "yield", EXPR_END],
|
134
|
+
[:TkSUPER, TkKW, "super", EXPR_END],
|
135
|
+
[:TkSELF, TkKW, "self", EXPR_END],
|
136
|
+
[:TkNIL, TkKW, "nil", EXPR_END],
|
137
|
+
[:TkTRUE, TkKW, "true", EXPR_END],
|
138
|
+
[:TkFALSE, TkKW, "false", EXPR_END],
|
139
|
+
[:TkAND, TkKW, "and", EXPR_BEG],
|
140
|
+
[:TkOR, TkKW, "or", EXPR_BEG],
|
141
|
+
[:TkNOT, TkKW, "not", EXPR_BEG],
|
142
|
+
[:TkIF_MOD, TkKW],
|
143
|
+
[:TkUNLESS_MOD, TkKW],
|
144
|
+
[:TkWHILE_MOD, TkKW],
|
145
|
+
[:TkUNTIL_MOD, TkKW],
|
146
|
+
[:TkALIAS, TkKW, "alias", EXPR_FNAME],
|
147
|
+
[:TkDEFINED, TkKW, "defined?", EXPR_END],
|
148
|
+
[:TklBEGIN, TkKW, "BEGIN", EXPR_END],
|
149
|
+
[:TklEND, TkKW, "END", EXPR_END],
|
150
|
+
[:Tk__LINE__, TkKW, "__LINE__", EXPR_END],
|
151
|
+
[:Tk__FILE__, TkKW, "__FILE__", EXPR_END],
|
152
|
+
|
153
|
+
[:TkIDENTIFIER, TkId],
|
154
|
+
[:TkFID, TkId],
|
155
|
+
[:TkGVAR, TkId],
|
156
|
+
[:TkIVAR, TkId],
|
157
|
+
[:TkCONSTANT, TkId],
|
158
|
+
|
159
|
+
[:TkINTEGER, TkVal],
|
160
|
+
[:TkFLOAT, TkVal],
|
161
|
+
[:TkSTRING, TkVal],
|
162
|
+
[:TkXSTRING, TkVal],
|
163
|
+
[:TkREGEXP, TkVal],
|
164
|
+
[:TkCOMMENT, TkVal],
|
165
|
+
|
166
|
+
[:TkDSTRING, TkNode],
|
167
|
+
[:TkDXSTRING, TkNode],
|
168
|
+
[:TkDREGEXP, TkNode],
|
169
|
+
[:TkNTH_REF, TkId],
|
170
|
+
[:TkBACK_REF, TkId],
|
171
|
+
|
172
|
+
[:TkUPLUS, TkOp, "+@"],
|
173
|
+
[:TkUMINUS, TkOp, "-@"],
|
174
|
+
[:TkPOW, TkOp, "**"],
|
175
|
+
[:TkCMP, TkOp, "<=>"],
|
176
|
+
[:TkEQ, TkOp, "=="],
|
177
|
+
[:TkEQQ, TkOp, "==="],
|
178
|
+
[:TkNEQ, TkOp, "!="],
|
179
|
+
[:TkGEQ, TkOp, ">="],
|
180
|
+
[:TkLEQ, TkOp, "<="],
|
181
|
+
[:TkANDOP, TkOp, "&&"],
|
182
|
+
[:TkOROP, TkOp, "||"],
|
183
|
+
[:TkMATCH, TkOp, "=~"],
|
184
|
+
[:TkNMATCH, TkOp, "!~"],
|
185
|
+
[:TkDOT2, TkOp, ".."],
|
186
|
+
[:TkDOT3, TkOp, "..."],
|
187
|
+
[:TkAREF, TkOp, "[]"],
|
188
|
+
[:TkASET, TkOp, "[]="],
|
189
|
+
[:TkLSHFT, TkOp, "<<"],
|
190
|
+
[:TkRSHFT, TkOp, ">>"],
|
191
|
+
[:TkCOLON2, TkOp],
|
192
|
+
[:TkCOLON3, TkOp],
|
193
|
+
[:OPASGN, TkOp], # +=, -= etc. #
|
194
|
+
[:TkASSOC, TkOp, "=>"],
|
195
|
+
[:TkQUESTION, TkOp, "?"], #?
|
196
|
+
[:TkCOLON, TkOp, ":"], #:
|
196
197
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
198
|
+
[:TkfLPAREN], # func( #
|
199
|
+
[:TkfLBRACK], # func[ #
|
200
|
+
[:TkfLBRACE], # func{ #
|
201
|
+
[:TkSTAR], # *arg
|
202
|
+
[:TkAMPER], # &arg #
|
203
|
+
[:TkSYMBOL, TkId], # :SYMBOL
|
204
|
+
[:TkSYMBEG, TkId],
|
205
|
+
[:TkGT, TkOp, ">"],
|
206
|
+
[:TkLT, TkOp, "<"],
|
207
|
+
[:TkPLUS, TkOp, "+"],
|
208
|
+
[:TkMINUS, TkOp, "-"],
|
209
|
+
[:TkMULT, TkOp, "*"],
|
210
|
+
[:TkDIV, TkOp, "/"],
|
211
|
+
[:TkMOD, TkOp, "%"],
|
212
|
+
[:TkBITOR, TkOp, "|"],
|
213
|
+
[:TkBITXOR, TkOp, "^"],
|
214
|
+
[:TkBITAND, TkOp, "&"],
|
215
|
+
[:TkBITNOT, TkOp, "~"],
|
216
|
+
[:TkNOTOP, TkOp, "!"],
|
217
|
+
|
218
|
+
[:TkBACKQUOTE, TkOp, "`"],
|
219
|
+
|
220
|
+
[:TkASSIGN, Token, "="],
|
221
|
+
[:TkDOT, Token, "."],
|
222
|
+
[:TkLPAREN, Token, "("], #(exp)
|
223
|
+
[:TkLBRACK, Token, "["], #[arry]
|
224
|
+
[:TkLBRACE, Token, "{"], #{hash}
|
225
|
+
[:TkRPAREN, Token, ")"],
|
226
|
+
[:TkRBRACK, Token, "]"],
|
227
|
+
[:TkRBRACE, Token, "}"],
|
228
|
+
[:TkCOMMA, Token, ","],
|
229
|
+
[:TkSEMICOLON, Token, ";"],
|
230
|
+
|
231
|
+
[:TkRD_COMMENT],
|
232
|
+
[:TkSPACE],
|
233
|
+
[:TkNL],
|
234
|
+
[:TkEND_OF_SCRIPT],
|
235
|
+
|
236
|
+
[:TkBACKSLASH, TkUnknownChar, "\\"],
|
237
|
+
[:TkAT, TkUnknownChar, "@"],
|
238
|
+
[:TkDOLLAR, TkUnknownChar, "\$"], #"
|
239
|
+
]
|
240
|
+
|
241
|
+
# {reading => token_class}
|
242
|
+
# {reading => [token_class, *opt]}
|
243
|
+
TkReading2Token = {}
|
244
|
+
TkSymbol2Token = {}
|
245
|
+
|
246
|
+
def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts)
|
247
|
+
token_n = token_n.id2name unless token_n.kind_of?(String)
|
248
|
+
if RubyToken.const_defined?(token_n)
|
249
|
+
#IRB.fail AlreadyDefinedToken, token_n
|
250
|
+
end
|
250
251
|
|
251
|
-
|
252
|
-
|
253
|
-
# token_c.inspect
|
252
|
+
token_c = Class.new super_token
|
253
|
+
RubyToken.const_set token_n, token_c
|
254
|
+
# token_c.inspect
|
254
255
|
|
255
|
-
|
256
|
-
|
257
|
-
|
256
|
+
if reading
|
257
|
+
if TkReading2Token[reading]
|
258
|
+
IRB.fail TkReading2TokenDuplicateError, token_n, reading
|
259
|
+
end
|
260
|
+
if opts.empty?
|
261
|
+
TkReading2Token[reading] = [token_c]
|
262
|
+
else
|
263
|
+
TkReading2Token[reading] = [token_c].concat(opts)
|
264
|
+
end
|
258
265
|
end
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
266
|
+
TkSymbol2Token[token_n.intern] = token_c
|
267
|
+
|
268
|
+
if token_c <= TkOp
|
269
|
+
token_c.class_eval %{
|
270
|
+
def self.op_name; "#{reading}"; end
|
271
|
+
}
|
263
272
|
end
|
264
273
|
end
|
265
|
-
TkSymbol2Token[token_n.intern] = token_c
|
266
274
|
|
267
|
-
|
268
|
-
|
269
|
-
def self.op_name; "#{reading}"; end
|
270
|
-
}
|
275
|
+
for defs in TokenDefinitions
|
276
|
+
def_token(*defs)
|
271
277
|
end
|
272
|
-
end
|
273
278
|
|
274
|
-
|
275
|
-
|
279
|
+
NEWLINE_TOKEN = TkNL.new(0,0)
|
280
|
+
NEWLINE_TOKEN.set_text("\n")
|
281
|
+
|
276
282
|
end
|
277
283
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
#
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
# When the lexer encounters the <<A, it reads until the end of the
|
314
|
-
# line, and keeps it around for later. It then reads the body of the
|
315
|
-
# here document. Once complete, it needs to read the rest of the
|
316
|
-
# original line, but then skip the here document body.
|
317
|
-
#
|
284
|
+
|
285
|
+
|
286
|
+
# Lexical analyzer for Ruby source
|
287
|
+
|
288
|
+
class RubyLex
|
289
|
+
|
290
|
+
######################################################################
|
291
|
+
#
|
292
|
+
# Read an input stream character by character. We allow for unlimited
|
293
|
+
# ungetting of characters just read.
|
294
|
+
#
|
295
|
+
# We simplify the implementation greatly by reading the entire input
|
296
|
+
# into a buffer initially, and then simply traversing it using
|
297
|
+
# pointers.
|
298
|
+
#
|
299
|
+
# We also have to allow for the <i>here document diversion</i>. This
|
300
|
+
# little gem comes about when the lexer encounters a here
|
301
|
+
# document. At this point we effectively need to split the input
|
302
|
+
# stream into two parts: one to read the body of the here document,
|
303
|
+
# the other to read the rest of the input line where the here
|
304
|
+
# document was initially encountered. For example, we might have
|
305
|
+
#
|
306
|
+
# do_something(<<-A, <<-B)
|
307
|
+
# stuff
|
308
|
+
# for
|
309
|
+
# A
|
310
|
+
# stuff
|
311
|
+
# for
|
312
|
+
# B
|
313
|
+
#
|
314
|
+
# When the lexer encounters the <<A, it reads until the end of the
|
315
|
+
# line, and keeps it around for later. It then reads the body of the
|
316
|
+
# here document. Once complete, it needs to read the rest of the
|
317
|
+
# original line, but then skip the here document body.
|
318
|
+
#
|
318
319
|
|
319
|
-
|
320
|
+
class BufferedReader
|
320
321
|
|
321
|
-
|
322
|
+
attr_reader :line_num
|
322
323
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
324
|
+
def initialize(content)
|
325
|
+
if /\t/ =~ content
|
326
|
+
tab_width = 2
|
327
|
+
content = content.split(/\n/).map do |line|
|
328
|
+
1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
|
329
|
+
line
|
330
|
+
end .join("\n")
|
331
|
+
end
|
332
|
+
@content = content
|
333
|
+
@content << "\n" unless @content[-1,1] == "\n"
|
334
|
+
@size = @content.size
|
335
|
+
@offset = 0
|
336
|
+
@hwm = 0
|
337
|
+
@line_num = 1
|
338
|
+
@read_back_offset = 0
|
339
|
+
@last_newline = 0
|
340
|
+
@newline_pending = false
|
341
|
+
end
|
341
342
|
|
342
|
-
|
343
|
-
|
344
|
-
|
343
|
+
def column
|
344
|
+
@offset - @last_newline
|
345
|
+
end
|
345
346
|
|
346
|
-
|
347
|
-
|
348
|
-
|
347
|
+
def getc
|
348
|
+
return nil if @offset >= @size
|
349
|
+
ch = @content[@offset, 1]
|
349
350
|
|
350
|
-
|
351
|
-
|
351
|
+
@offset += 1
|
352
|
+
@hwm = @offset if @hwm < @offset
|
352
353
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
354
|
+
if @newline_pending
|
355
|
+
@line_num += 1
|
356
|
+
@last_newline = @offset - 1
|
357
|
+
@newline_pending = false
|
358
|
+
end
|
358
359
|
|
359
|
-
|
360
|
-
|
360
|
+
if ch == "\n"
|
361
|
+
@newline_pending = true
|
362
|
+
end
|
363
|
+
ch
|
361
364
|
end
|
362
|
-
ch
|
363
|
-
end
|
364
365
|
|
365
|
-
|
366
|
-
|
367
|
-
|
366
|
+
def getc_already_read
|
367
|
+
getc
|
368
|
+
end
|
368
369
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
370
|
+
def ungetc(ch)
|
371
|
+
raise "unget past beginning of file" if @offset <= 0
|
372
|
+
@offset -= 1
|
373
|
+
if @content[@offset] == ?\n
|
374
|
+
@newline_pending = false
|
375
|
+
end
|
374
376
|
end
|
375
|
-
end
|
376
377
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
378
|
+
def get_read
|
379
|
+
res = @content[@read_back_offset...@offset]
|
380
|
+
@read_back_offset = @offset
|
381
|
+
res
|
382
|
+
end
|
382
383
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
384
|
+
def peek(at)
|
385
|
+
pos = @offset + at
|
386
|
+
if pos >= @size
|
387
|
+
nil
|
388
|
+
else
|
389
|
+
@content[pos, 1]
|
390
|
+
end
|
389
391
|
end
|
390
|
-
end
|
391
392
|
|
392
|
-
|
393
|
-
|
394
|
-
|
393
|
+
def peek_equal(str)
|
394
|
+
@content[@offset, str.length] == str
|
395
|
+
end
|
395
396
|
|
396
|
-
|
397
|
-
|
398
|
-
|
397
|
+
def divert_read_from(reserve)
|
398
|
+
@content[@offset, 0] = reserve
|
399
|
+
@size = @content.size
|
400
|
+
end
|
399
401
|
end
|
400
|
-
end
|
401
402
|
|
402
|
-
|
403
|
+
# end of nested class BufferedReader
|
403
404
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
405
|
+
extend Exception2MessageMapper
|
406
|
+
def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
|
407
|
+
def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
|
408
|
+
def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
|
409
|
+
def_exception(:TkReading2TokenDuplicateError,
|
410
|
+
"key duplicate(token_n='%s', key='%s')")
|
411
|
+
def_exception(:SyntaxError, "%s")
|
411
412
|
|
412
|
-
|
413
|
-
|
413
|
+
include RubyToken
|
414
|
+
include IRB
|
414
415
|
|
415
|
-
|
416
|
-
|
416
|
+
attr_reader :continue
|
417
|
+
attr_reader :lex_state
|
417
418
|
|
418
|
-
|
419
|
-
|
420
|
-
|
419
|
+
def RubyLex.debug?
|
420
|
+
false
|
421
|
+
end
|
421
422
|
|
422
|
-
|
423
|
-
|
423
|
+
def initialize(content)
|
424
|
+
lex_init
|
424
425
|
|
425
|
-
|
426
|
+
@reader = BufferedReader.new(content)
|
426
427
|
|
427
|
-
|
428
|
-
|
429
|
-
|
428
|
+
@exp_line_no = @line_no = 1
|
429
|
+
@base_char_no = 0
|
430
|
+
@indent = 0
|
430
431
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
432
|
+
@ltype = nil
|
433
|
+
@quoted = nil
|
434
|
+
@lex_state = EXPR_BEG
|
435
|
+
@space_seen = false
|
435
436
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
@skip_space = false
|
440
|
-
@read_auto_clean_up = false
|
441
|
-
@exception_on_syntax_error = true
|
442
|
-
end
|
437
|
+
@continue = false
|
438
|
+
@line = ""
|
443
439
|
|
444
|
-
|
445
|
-
|
446
|
-
|
440
|
+
@skip_space = false
|
441
|
+
@read_auto_clean_up = false
|
442
|
+
@exception_on_syntax_error = true
|
443
|
+
end
|
447
444
|
|
448
|
-
|
445
|
+
attr :skip_space, true
|
446
|
+
attr :read_auto_clean_up, true
|
447
|
+
attr :exception_on_syntax_error, true
|
449
448
|
|
450
|
-
|
451
|
-
def line_no
|
452
|
-
@reader.line_num
|
453
|
-
end
|
449
|
+
attr :indent
|
454
450
|
|
455
|
-
|
456
|
-
|
457
|
-
|
451
|
+
# io functions
|
452
|
+
def line_no
|
453
|
+
@reader.line_num
|
454
|
+
end
|
458
455
|
|
459
|
-
|
460
|
-
|
461
|
-
|
456
|
+
def char_no
|
457
|
+
@reader.column
|
458
|
+
end
|
462
459
|
|
463
|
-
|
464
|
-
|
465
|
-
|
460
|
+
def get_read
|
461
|
+
@reader.get_read
|
462
|
+
end
|
466
463
|
|
467
|
-
|
468
|
-
|
469
|
-
|
464
|
+
def getc
|
465
|
+
@reader.getc
|
466
|
+
end
|
470
467
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
begin
|
475
|
-
l.concat c unless c == "\r"
|
476
|
-
break if c == "\n"
|
477
|
-
end while c = getc
|
478
|
-
l
|
479
|
-
end
|
468
|
+
def getc_of_rests
|
469
|
+
@reader.getc_already_read
|
470
|
+
end
|
480
471
|
|
472
|
+
def gets
|
473
|
+
c = getc or return
|
474
|
+
l = ""
|
475
|
+
begin
|
476
|
+
l.concat c unless c == "\r"
|
477
|
+
break if c == "\n"
|
478
|
+
end while c = getc
|
479
|
+
l
|
480
|
+
end
|
481
481
|
|
482
|
-
def ungetc(c = nil)
|
483
|
-
@reader.ungetc(c)
|
484
|
-
end
|
485
482
|
|
486
|
-
|
487
|
-
|
488
|
-
|
483
|
+
def ungetc(c = nil)
|
484
|
+
@reader.ungetc(c)
|
485
|
+
end
|
489
486
|
|
490
|
-
|
491
|
-
|
492
|
-
|
487
|
+
def peek_equal?(str)
|
488
|
+
@reader.peek_equal(str)
|
489
|
+
end
|
493
490
|
|
494
|
-
|
495
|
-
|
496
|
-
!@continue or
|
497
|
-
tk.nil?)
|
491
|
+
def peek(i = 0)
|
492
|
+
@reader.peek(i)
|
498
493
|
end
|
499
|
-
line = get_read
|
500
494
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
495
|
+
def lex
|
496
|
+
until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) &&
|
497
|
+
!@continue or
|
498
|
+
tk.nil?)
|
499
|
+
end
|
500
|
+
line = get_read
|
501
|
+
|
502
|
+
if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil?
|
503
|
+
nil
|
504
|
+
else
|
505
|
+
line
|
506
|
+
end
|
505
507
|
end
|
506
|
-
end
|
507
508
|
|
508
|
-
|
509
|
-
|
510
|
-
begin
|
509
|
+
def token
|
510
|
+
set_token_position(line_no, char_no)
|
511
511
|
begin
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
512
|
+
begin
|
513
|
+
tk = @OP.match(self)
|
514
|
+
@space_seen = tk.kind_of?(TkSPACE)
|
515
|
+
rescue SyntaxError
|
516
|
+
abort if @exception_on_syntax_error
|
517
|
+
tk = TkError.new(line_no, char_no)
|
518
|
+
end
|
519
|
+
end while @skip_space and tk.kind_of?(TkSPACE)
|
520
|
+
if @read_auto_clean_up
|
521
|
+
get_read
|
522
|
+
end
|
523
|
+
# throw :eof unless tk
|
524
|
+
p tk if $DEBUG
|
525
|
+
tk.lex_state = lex_state if tk
|
526
|
+
tk
|
521
527
|
end
|
522
|
-
# throw :eof unless tk
|
523
|
-
p tk if $DEBUG
|
524
|
-
tk.lex_state = lex_state if tk
|
525
|
-
tk
|
526
|
-
end
|
527
528
|
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
529
|
+
ENINDENT_CLAUSE = [
|
530
|
+
"case", "class", "def", "do", "for", "if",
|
531
|
+
"module", "unless", "until", "while", "begin" #, "when"
|
532
|
+
]
|
533
|
+
DEINDENT_CLAUSE = ["end" #, "when"
|
534
|
+
]
|
535
|
+
|
536
|
+
PERCENT_LTYPE = {
|
537
|
+
"q" => "\'",
|
538
|
+
"Q" => "\"",
|
539
|
+
"x" => "\`",
|
540
|
+
"r" => "/",
|
541
|
+
"w" => "]",
|
542
|
+
"W" => "]"
|
543
|
+
}
|
542
544
|
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
545
|
+
PERCENT_PAREN = {
|
546
|
+
"{" => "}",
|
547
|
+
"[" => "]",
|
548
|
+
"<" => ">",
|
549
|
+
"(" => ")"
|
550
|
+
}
|
551
|
+
|
552
|
+
Ltype2Token = {
|
553
|
+
"\'" => TkSTRING,
|
554
|
+
"\"" => TkSTRING,
|
555
|
+
"\`" => TkXSTRING,
|
556
|
+
"/" => TkREGEXP,
|
557
|
+
"]" => TkDSTRING
|
558
|
+
}
|
559
|
+
Ltype2Token.default = TkSTRING
|
560
|
+
|
561
|
+
DLtype2Token = {
|
562
|
+
"\"" => TkDSTRING,
|
563
|
+
"\`" => TkDXSTRING,
|
564
|
+
"/" => TkDREGEXP,
|
565
|
+
}
|
566
|
+
|
567
|
+
def lex_init()
|
568
|
+
@OP = SLex.new
|
569
|
+
@OP.def_rules("\0", "\004", "\032") do |chars, io|
|
570
|
+
Token(TkEND_OF_SCRIPT).set_text(chars)
|
571
|
+
end
|
570
572
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
573
|
+
@OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io|
|
574
|
+
@space_seen = TRUE
|
575
|
+
while (ch = getc) =~ /[ \t\f\r\13]/
|
576
|
+
chars << ch
|
577
|
+
end
|
578
|
+
ungetc
|
579
|
+
Token(TkSPACE).set_text(chars)
|
575
580
|
end
|
576
|
-
ungetc
|
577
|
-
Token(TkSPACE).set_text(chars)
|
578
|
-
end
|
579
581
|
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
582
|
+
@OP.def_rule("#") do
|
583
|
+
|op, io|
|
584
|
+
identify_comment
|
585
|
+
end
|
584
586
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
587
|
+
@OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do
|
588
|
+
|op, io|
|
589
|
+
str = op
|
590
|
+
@ltype = "="
|
589
591
|
|
590
592
|
|
591
|
-
begin
|
592
|
-
line = ""
|
593
593
|
begin
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
594
|
+
line = ""
|
595
|
+
begin
|
596
|
+
ch = getc
|
597
|
+
line << ch
|
598
|
+
end until ch == "\n"
|
599
|
+
str << line
|
600
|
+
end until line =~ /^=end/
|
601
|
+
|
602
|
+
ungetc
|
603
|
+
|
604
|
+
@ltype = nil
|
605
|
+
|
606
|
+
if str =~ /\A=begin\s+rdoc/i
|
607
|
+
str.sub!(/\A=begin.*\n/, '')
|
608
|
+
str.sub!(/^=end.*/m, '')
|
609
|
+
Token(TkCOMMENT).set_text(str)
|
610
|
+
else
|
611
|
+
Token(TkRD_COMMENT)#.set_text(str)
|
612
|
+
end
|
613
|
+
end
|
599
614
|
|
600
|
-
|
615
|
+
@OP.def_rule("\n") do
|
616
|
+
print "\\n\n" if RubyLex.debug?
|
617
|
+
case @lex_state
|
618
|
+
when EXPR_BEG, EXPR_FNAME, EXPR_DOT
|
619
|
+
@continue = TRUE
|
620
|
+
else
|
621
|
+
@continue = FALSE
|
622
|
+
@lex_state = EXPR_BEG
|
623
|
+
end
|
624
|
+
Token(TkNL).set_text("\n")
|
625
|
+
end
|
601
626
|
|
602
|
-
@
|
627
|
+
@OP.def_rules("*", "**",
|
628
|
+
"!", "!=", "!~",
|
629
|
+
"=", "==", "===",
|
630
|
+
"=~", "<=>",
|
631
|
+
"<", "<=",
|
632
|
+
">", ">=", ">>") do |op, io|
|
633
|
+
@lex_state = EXPR_BEG
|
634
|
+
Token(op).set_text(op)
|
635
|
+
end
|
603
636
|
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
637
|
+
@OP.def_rules("<<") do |op, io|
|
638
|
+
tk = nil
|
639
|
+
if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
|
640
|
+
(@lex_state != EXPR_ARG || @space_seen)
|
641
|
+
c = peek(0)
|
642
|
+
tk = identify_here_document if /[-\w_\"\'\`]/ =~ c
|
643
|
+
end
|
644
|
+
if !tk
|
645
|
+
@lex_state = EXPR_BEG
|
646
|
+
tk = Token(op).set_text(op)
|
647
|
+
end
|
648
|
+
tk
|
610
649
|
end
|
611
|
-
end
|
612
650
|
|
613
|
-
|
614
|
-
|
615
|
-
case @lex_state
|
616
|
-
when EXPR_BEG, EXPR_FNAME, EXPR_DOT
|
617
|
-
@continue = TRUE
|
618
|
-
else
|
619
|
-
@continue = FALSE
|
620
|
-
@lex_state = EXPR_BEG
|
651
|
+
@OP.def_rules("'", '"') do |op, io|
|
652
|
+
identify_string(op)
|
621
653
|
end
|
622
|
-
Token(TkNL).set_text("\n")
|
623
|
-
end
|
624
654
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
Token(op).set_text(op)
|
633
|
-
end
|
655
|
+
@OP.def_rules("`") do |op, io|
|
656
|
+
if @lex_state == EXPR_FNAME
|
657
|
+
Token(op).set_text(op)
|
658
|
+
else
|
659
|
+
identify_string(op)
|
660
|
+
end
|
661
|
+
end
|
634
662
|
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
663
|
+
@OP.def_rules('?') do |op, io|
|
664
|
+
if @lex_state == EXPR_END
|
665
|
+
@lex_state = EXPR_BEG
|
666
|
+
Token(TkQUESTION).set_text(op)
|
667
|
+
else
|
668
|
+
ch = getc
|
669
|
+
if @lex_state == EXPR_ARG && ch !~ /\s/
|
670
|
+
ungetc
|
671
|
+
@lex_state = EXPR_BEG
|
672
|
+
Token(TkQUESTION).set_text(op)
|
673
|
+
else
|
674
|
+
str = op
|
675
|
+
str << ch
|
676
|
+
if (ch == '\\') #'
|
677
|
+
str << read_escape
|
678
|
+
end
|
679
|
+
@lex_state = EXPR_END
|
680
|
+
Token(TkINTEGER).set_text(str)
|
681
|
+
end
|
682
|
+
end
|
641
683
|
end
|
642
|
-
|
684
|
+
|
685
|
+
@OP.def_rules("&", "&&", "|", "||") do |op, io|
|
643
686
|
@lex_state = EXPR_BEG
|
644
|
-
|
687
|
+
Token(op).set_text(op)
|
645
688
|
end
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
@OP.def_rules("`") do |op, io|
|
654
|
-
if @lex_state == EXPR_FNAME
|
655
|
-
Token(op).set_text(op)
|
656
|
-
else
|
657
|
-
identify_string(op)
|
689
|
+
|
690
|
+
@OP.def_rules("+=", "-=", "*=", "**=",
|
691
|
+
"&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io|
|
692
|
+
@lex_state = EXPR_BEG
|
693
|
+
op =~ /^(.*)=$/
|
694
|
+
Token(TkOPASGN, $1).set_text(op)
|
658
695
|
end
|
659
|
-
end
|
660
696
|
|
661
|
-
|
662
|
-
|
663
|
-
@lex_state = EXPR_BEG
|
664
|
-
Token(TkQUESTION).set_text(op)
|
665
|
-
else
|
666
|
-
ch = getc
|
667
|
-
if @lex_state == EXPR_ARG && ch !~ /\s/
|
668
|
-
ungetc
|
669
|
-
@lex_state = EXPR_BEG
|
670
|
-
Token(TkQUESTION).set_text(op)
|
671
|
-
else
|
672
|
-
str = op
|
673
|
-
str << ch
|
674
|
-
if (ch == '\\') #'
|
675
|
-
str << read_escape
|
676
|
-
end
|
677
|
-
@lex_state = EXPR_END
|
678
|
-
Token(TkINTEGER).set_text(str)
|
679
|
-
end
|
697
|
+
@OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io|
|
698
|
+
Token(TkUPLUS).set_text(op)
|
680
699
|
end
|
681
|
-
end
|
682
700
|
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
end
|
687
|
-
|
688
|
-
@OP.def_rules("+=", "-=", "*=", "**=",
|
689
|
-
"&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io|
|
690
|
-
@lex_state = EXPR_BEG
|
691
|
-
op =~ /^(.*)=$/
|
692
|
-
Token(TkOPASGN, $1).set_text(op)
|
693
|
-
end
|
694
|
-
|
695
|
-
@OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io|
|
696
|
-
Token(TkUPLUS).set_text(op)
|
697
|
-
end
|
701
|
+
@OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io|
|
702
|
+
Token(TkUMINUS).set_text(op)
|
703
|
+
end
|
698
704
|
|
699
|
-
|
700
|
-
|
701
|
-
|
705
|
+
@OP.def_rules("+", "-") do |op, io|
|
706
|
+
catch(:RET) do
|
707
|
+
if @lex_state == EXPR_ARG
|
708
|
+
if @space_seen and peek(0) =~ /[0-9]/
|
709
|
+
throw :RET, identify_number(op)
|
710
|
+
else
|
711
|
+
@lex_state = EXPR_BEG
|
712
|
+
end
|
713
|
+
elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
|
714
|
+
throw :RET, identify_number(op)
|
715
|
+
else
|
716
|
+
@lex_state = EXPR_BEG
|
717
|
+
end
|
718
|
+
Token(op).set_text(op)
|
719
|
+
end
|
720
|
+
end
|
702
721
|
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
else
|
714
|
-
@lex_state = EXPR_BEG
|
715
|
-
end
|
716
|
-
Token(op).set_text(op)
|
722
|
+
@OP.def_rule(".") do
|
723
|
+
@lex_state = EXPR_BEG
|
724
|
+
if peek(0) =~ /[0-9]/
|
725
|
+
ungetc
|
726
|
+
identify_number("")
|
727
|
+
else
|
728
|
+
# for obj.if
|
729
|
+
@lex_state = EXPR_DOT
|
730
|
+
Token(TkDOT).set_text(".")
|
731
|
+
end
|
717
732
|
end
|
718
|
-
end
|
719
733
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
ungetc
|
724
|
-
identify_number("")
|
725
|
-
else
|
726
|
-
# for obj.if
|
727
|
-
@lex_state = EXPR_DOT
|
728
|
-
Token(TkDOT).set_text(".")
|
734
|
+
@OP.def_rules("..", "...") do |op, io|
|
735
|
+
@lex_state = EXPR_BEG
|
736
|
+
Token(op).set_text(op)
|
729
737
|
end
|
730
|
-
end
|
731
738
|
|
732
|
-
|
733
|
-
@lex_state = EXPR_BEG
|
734
|
-
Token(op).set_text(op)
|
739
|
+
lex_int2
|
735
740
|
end
|
736
|
-
|
737
|
-
lex_int2
|
738
|
-
end
|
739
741
|
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
742
|
+
def lex_int2
|
743
|
+
@OP.def_rules("]", "}", ")") do
|
744
|
+
|op, io|
|
745
|
+
@lex_state = EXPR_END
|
746
|
+
@indent -= 1
|
747
|
+
Token(op).set_text(op)
|
748
|
+
end
|
747
749
|
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
750
|
+
@OP.def_rule(":") do
|
751
|
+
if @lex_state == EXPR_END || peek(0) =~ /\s/
|
752
|
+
@lex_state = EXPR_BEG
|
753
|
+
tk = Token(TkCOLON)
|
754
|
+
else
|
755
|
+
@lex_state = EXPR_FNAME
|
756
|
+
tk = Token(TkSYMBEG)
|
757
|
+
end
|
758
|
+
tk.set_text(":")
|
755
759
|
end
|
756
|
-
tk.set_text(":")
|
757
|
-
end
|
758
760
|
|
759
|
-
|
760
|
-
# p @lex_state.id2name, @space_seen
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
761
|
+
@OP.def_rule("::") do
|
762
|
+
# p @lex_state.id2name, @space_seen
|
763
|
+
if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
|
764
|
+
@lex_state = EXPR_BEG
|
765
|
+
tk = Token(TkCOLON3)
|
766
|
+
else
|
767
|
+
@lex_state = EXPR_DOT
|
768
|
+
tk = Token(TkCOLON2)
|
769
|
+
end
|
770
|
+
tk.set_text("::")
|
767
771
|
end
|
768
|
-
tk.set_text("::")
|
769
|
-
end
|
770
772
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
773
|
+
@OP.def_rule("/") do |op, io|
|
774
|
+
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
775
|
+
identify_string(op)
|
776
|
+
elsif peek(0) == '='
|
777
|
+
getc
|
778
|
+
@lex_state = EXPR_BEG
|
779
|
+
Token(TkOPASGN, :/).set_text("/=") #")
|
780
|
+
elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
|
781
|
+
identify_string(op)
|
782
|
+
else
|
783
|
+
@lex_state = EXPR_BEG
|
784
|
+
Token("/").set_text(op)
|
785
|
+
end
|
783
786
|
end
|
784
|
-
end
|
785
787
|
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
788
|
+
@OP.def_rules("^") do
|
789
|
+
@lex_state = EXPR_BEG
|
790
|
+
Token("^").set_text("^")
|
791
|
+
end
|
790
792
|
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
793
|
+
# @OP.def_rules("^=") do
|
794
|
+
# @lex_state = EXPR_BEG
|
795
|
+
# Token(TkOPASGN, :^)
|
796
|
+
# end
|
795
797
|
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
798
|
+
@OP.def_rules(",", ";") do |op, io|
|
799
|
+
@lex_state = EXPR_BEG
|
800
|
+
Token(op).set_text(op)
|
801
|
+
end
|
800
802
|
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
803
|
+
@OP.def_rule("~") do
|
804
|
+
@lex_state = EXPR_BEG
|
805
|
+
Token("~").set_text("~")
|
806
|
+
end
|
805
807
|
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
808
|
+
@OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do
|
809
|
+
@lex_state = EXPR_BEG
|
810
|
+
Token("~").set_text("~@")
|
811
|
+
end
|
810
812
|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
813
|
+
@OP.def_rule("(") do
|
814
|
+
@indent += 1
|
815
|
+
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
816
|
+
@lex_state = EXPR_BEG
|
817
|
+
tk = Token(TkfLPAREN)
|
818
|
+
else
|
819
|
+
@lex_state = EXPR_BEG
|
820
|
+
tk = Token(TkLPAREN)
|
821
|
+
end
|
822
|
+
tk.set_text("(")
|
819
823
|
end
|
820
|
-
tk.set_text("(")
|
821
|
-
end
|
822
824
|
|
823
|
-
|
824
|
-
|
825
|
-
|
825
|
+
@OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do
|
826
|
+
Token("[]").set_text("[]")
|
827
|
+
end
|
826
828
|
|
827
|
-
|
828
|
-
|
829
|
-
|
829
|
+
@OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do
|
830
|
+
Token("[]=").set_text("[]=")
|
831
|
+
end
|
830
832
|
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
833
|
+
@OP.def_rule("[") do
|
834
|
+
@indent += 1
|
835
|
+
if @lex_state == EXPR_FNAME
|
836
|
+
t = Token(TkfLBRACK)
|
837
|
+
else
|
838
|
+
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
839
|
+
t = Token(TkLBRACK)
|
840
|
+
elsif @lex_state == EXPR_ARG && @space_seen
|
841
|
+
t = Token(TkLBRACK)
|
842
|
+
else
|
843
|
+
t = Token(TkfLBRACK)
|
844
|
+
end
|
845
|
+
@lex_state = EXPR_BEG
|
846
|
+
end
|
847
|
+
t.set_text("[")
|
848
|
+
end
|
847
849
|
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
850
|
+
@OP.def_rule("{") do
|
851
|
+
@indent += 1
|
852
|
+
if @lex_state != EXPR_END && @lex_state != EXPR_ARG
|
853
|
+
t = Token(TkLBRACE)
|
854
|
+
else
|
855
|
+
t = Token(TkfLBRACE)
|
856
|
+
end
|
857
|
+
@lex_state = EXPR_BEG
|
858
|
+
t.set_text("{")
|
854
859
|
end
|
855
|
-
@lex_state = EXPR_BEG
|
856
|
-
t.set_text("{")
|
857
|
-
end
|
858
860
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
861
|
+
@OP.def_rule('\\') do #'
|
862
|
+
if getc == "\n"
|
863
|
+
@space_seen = true
|
864
|
+
@continue = true
|
865
|
+
Token(TkSPACE).set_text("\\\n")
|
866
|
+
else
|
867
|
+
ungetc
|
868
|
+
Token("\\").set_text("\\") #"
|
869
|
+
end
|
867
870
|
end
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
871
|
+
|
872
|
+
@OP.def_rule('%') do
|
873
|
+
|op, io|
|
874
|
+
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
875
|
+
identify_quotation('%')
|
876
|
+
elsif peek(0) == '='
|
877
|
+
getc
|
878
|
+
Token(TkOPASGN, "%").set_text("%=")
|
879
|
+
elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
|
880
|
+
identify_quotation('%')
|
881
|
+
else
|
882
|
+
@lex_state = EXPR_BEG
|
883
|
+
Token("%").set_text("%")
|
884
|
+
end
|
882
885
|
end
|
883
|
-
end
|
884
886
|
|
885
|
-
|
886
|
-
|
887
|
-
|
887
|
+
@OP.def_rule('$') do #'
|
888
|
+
identify_gvar
|
889
|
+
end
|
888
890
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
891
|
+
@OP.def_rule('@') do
|
892
|
+
if peek(0) =~ /[@\w_]/
|
893
|
+
ungetc
|
894
|
+
identify_identifier
|
895
|
+
else
|
896
|
+
Token("@").set_text("@")
|
897
|
+
end
|
895
898
|
end
|
896
|
-
end
|
897
899
|
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
900
|
+
# @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do
|
901
|
+
# |op, io|
|
902
|
+
# @indent += 1
|
903
|
+
# @lex_state = EXPR_FNAME
|
904
|
+
# # @lex_state = EXPR_END
|
905
|
+
# # until @rests[0] == "\n" or @rests[0] == ";"
|
906
|
+
# # rests.shift
|
907
|
+
# # end
|
908
|
+
# end
|
909
|
+
|
910
|
+
@OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do
|
911
|
+
throw :eof
|
912
|
+
end
|
911
913
|
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
914
|
+
@OP.def_rule("") do
|
915
|
+
|op, io|
|
916
|
+
printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug?
|
917
|
+
if peek(0) =~ /[0-9]/
|
918
|
+
t = identify_number("")
|
919
|
+
elsif peek(0) =~ /[\w_]/
|
920
|
+
t = identify_identifier
|
921
|
+
end
|
922
|
+
printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug?
|
923
|
+
t
|
919
924
|
end
|
920
|
-
printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug?
|
921
|
-
t
|
922
|
-
end
|
923
925
|
|
924
|
-
|
925
|
-
|
926
|
+
p @OP if RubyLex.debug?
|
927
|
+
end
|
926
928
|
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
929
|
+
def identify_gvar
|
930
|
+
@lex_state = EXPR_END
|
931
|
+
str = "$"
|
932
|
+
|
933
|
+
tk = case ch = getc
|
934
|
+
when /[~_*$?!@\/\\;,=:<>".]/ #"
|
935
|
+
str << ch
|
936
|
+
Token(TkGVAR, str)
|
935
937
|
|
936
|
-
|
937
|
-
|
938
|
-
|
938
|
+
when "-"
|
939
|
+
str << "-" << getc
|
940
|
+
Token(TkGVAR, str)
|
939
941
|
|
940
|
-
|
941
|
-
|
942
|
-
|
942
|
+
when "&", "`", "'", "+"
|
943
|
+
str << ch
|
944
|
+
Token(TkBACK_REF, str)
|
943
945
|
|
944
|
-
|
945
|
-
str << ch
|
946
|
-
while (ch = getc) =~ /[0-9]/
|
946
|
+
when /[1-9]/
|
947
947
|
str << ch
|
948
|
+
while (ch = getc) =~ /[0-9]/
|
949
|
+
str << ch
|
950
|
+
end
|
951
|
+
ungetc
|
952
|
+
Token(TkNTH_REF)
|
953
|
+
when /\w/
|
954
|
+
ungetc
|
955
|
+
ungetc
|
956
|
+
return identify_identifier
|
957
|
+
else
|
958
|
+
ungetc
|
959
|
+
Token("$")
|
948
960
|
end
|
949
|
-
|
950
|
-
Token(TkNTH_REF)
|
951
|
-
when /\w/
|
952
|
-
ungetc
|
953
|
-
ungetc
|
954
|
-
return identify_identifier
|
955
|
-
else
|
956
|
-
ungetc
|
957
|
-
Token("$")
|
958
|
-
end
|
959
|
-
tk.set_text(str)
|
960
|
-
end
|
961
|
-
|
962
|
-
def identify_identifier
|
963
|
-
token = ""
|
964
|
-
token.concat getc if peek(0) =~ /[$@]/
|
965
|
-
token.concat getc if peek(0) == "@"
|
966
|
-
|
967
|
-
while (ch = getc) =~ /\w|_/
|
968
|
-
print ":", ch, ":" if RubyLex.debug?
|
969
|
-
token.concat ch
|
961
|
+
tk.set_text(str)
|
970
962
|
end
|
971
|
-
|
963
|
+
|
964
|
+
def identify_identifier
|
965
|
+
token = ""
|
966
|
+
token.concat getc if peek(0) =~ /[$@]/
|
967
|
+
token.concat getc if peek(0) == "@"
|
968
|
+
|
969
|
+
while (ch = getc) =~ /\w|_/
|
970
|
+
print ":", ch, ":" if RubyLex.debug?
|
971
|
+
token.concat ch
|
972
|
+
end
|
973
|
+
ungetc
|
972
974
|
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
975
|
+
if ch == "!" or ch == "?"
|
976
|
+
token.concat getc
|
977
|
+
end
|
978
|
+
# fix token
|
977
979
|
|
978
|
-
|
980
|
+
# $stderr.puts "identifier - #{token}, state = #@lex_state"
|
979
981
|
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
982
|
+
case token
|
983
|
+
when /^\$/
|
984
|
+
return Token(TkGVAR, token).set_text(token)
|
985
|
+
when /^\@/
|
986
|
+
@lex_state = EXPR_END
|
987
|
+
return Token(TkIVAR, token).set_text(token)
|
988
|
+
end
|
987
989
|
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
990
|
+
if @lex_state != EXPR_DOT
|
991
|
+
print token, "\n" if RubyLex.debug?
|
992
|
+
|
993
|
+
token_c, *trans = TkReading2Token[token]
|
994
|
+
if token_c
|
995
|
+
# reserved word?
|
996
|
+
|
997
|
+
if (@lex_state != EXPR_BEG &&
|
998
|
+
@lex_state != EXPR_FNAME &&
|
999
|
+
trans[1])
|
1000
|
+
# modifiers
|
1001
|
+
token_c = TkSymbol2Token[trans[1]]
|
1002
|
+
@lex_state = trans[0]
|
1003
|
+
else
|
1004
|
+
if @lex_state != EXPR_FNAME
|
1005
|
+
if ENINDENT_CLAUSE.include?(token)
|
1006
|
+
@indent += 1
|
1007
|
+
elsif DEINDENT_CLAUSE.include?(token)
|
1008
|
+
@indent -= 1
|
1009
|
+
end
|
1010
|
+
@lex_state = trans[0]
|
1011
|
+
else
|
1012
|
+
@lex_state = EXPR_END
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
return Token(token_c, token).set_text(token)
|
1016
|
+
end
|
1014
1017
|
end
|
1015
|
-
end
|
1016
1018
|
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1019
|
+
if @lex_state == EXPR_FNAME
|
1020
|
+
@lex_state = EXPR_END
|
1021
|
+
if peek(0) == '='
|
1022
|
+
token.concat getc
|
1023
|
+
end
|
1024
|
+
elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
|
1025
|
+
@lex_state = EXPR_ARG
|
1026
|
+
else
|
1027
|
+
@lex_state = EXPR_END
|
1021
1028
|
end
|
1022
|
-
elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
|
1023
|
-
@lex_state = EXPR_ARG
|
1024
|
-
else
|
1025
|
-
@lex_state = EXPR_END
|
1026
|
-
end
|
1027
1029
|
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1030
|
+
if token[0, 1] =~ /[A-Z]/
|
1031
|
+
return Token(TkCONSTANT, token).set_text(token)
|
1032
|
+
elsif token[token.size - 1, 1] =~ /[!?]/
|
1033
|
+
return Token(TkFID, token).set_text(token)
|
1034
|
+
else
|
1035
|
+
return Token(TkIDENTIFIER, token).set_text(token)
|
1036
|
+
end
|
1034
1037
|
end
|
1035
|
-
end
|
1036
1038
|
|
1037
|
-
|
1038
|
-
ch = getc
|
1039
|
-
if ch == "-"
|
1039
|
+
def identify_here_document
|
1040
1040
|
ch = getc
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1041
|
+
if ch == "-"
|
1042
|
+
ch = getc
|
1043
|
+
indent = true
|
1044
|
+
end
|
1045
|
+
if /['"`]/ =~ ch # '
|
1046
|
+
lt = ch
|
1047
|
+
quoted = ""
|
1048
|
+
while (c = getc) && c != lt
|
1049
|
+
quoted.concat c
|
1050
|
+
end
|
1051
|
+
else
|
1052
|
+
lt = '"'
|
1053
|
+
quoted = ch.dup
|
1054
|
+
while (c = getc) && c =~ /\w/
|
1055
|
+
quoted.concat c
|
1056
|
+
end
|
1057
|
+
ungetc
|
1054
1058
|
end
|
1055
|
-
ungetc
|
1056
|
-
end
|
1057
1059
|
|
1058
|
-
|
1059
|
-
|
1060
|
+
ltback, @ltype = @ltype, lt
|
1061
|
+
reserve = ""
|
1060
1062
|
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1063
|
+
while ch = getc
|
1064
|
+
reserve << ch
|
1065
|
+
if ch == "\\" #"
|
1066
|
+
ch = getc
|
1067
|
+
reserve << ch
|
1068
|
+
elsif ch == "\n"
|
1069
|
+
break
|
1070
|
+
end
|
1068
1071
|
end
|
1069
|
-
end
|
1070
1072
|
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1073
|
+
str = ""
|
1074
|
+
while (l = gets)
|
1075
|
+
l.chomp!
|
1076
|
+
l.strip! if indent
|
1077
|
+
break if l == quoted
|
1078
|
+
str << l.chomp << "\n"
|
1079
|
+
end
|
1078
1080
|
|
1079
|
-
|
1081
|
+
@reader.divert_read_from(reserve)
|
1080
1082
|
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1083
|
+
@ltype = ltback
|
1084
|
+
@lex_state = EXPR_END
|
1085
|
+
Token(Ltype2Token[lt], str).set_text(str.dump)
|
1086
|
+
end
|
1085
1087
|
|
1086
|
-
|
1087
|
-
ch = getc
|
1088
|
-
if lt = PERCENT_LTYPE[ch]
|
1089
|
-
initial_char += ch
|
1088
|
+
def identify_quotation(initial_char)
|
1090
1089
|
ch = getc
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1090
|
+
if lt = PERCENT_LTYPE[ch]
|
1091
|
+
initial_char += ch
|
1092
|
+
ch = getc
|
1093
|
+
elsif ch =~ /\W/
|
1094
|
+
lt = "\""
|
1095
|
+
else
|
1096
|
+
RubyLex.fail SyntaxError, "unknown type of %string ('#{ch}')"
|
1097
|
+
end
|
1098
|
+
# if ch !~ /\W/
|
1099
|
+
# ungetc
|
1100
|
+
# next
|
1101
|
+
# end
|
1102
|
+
#@ltype = lt
|
1103
|
+
@quoted = ch unless @quoted = PERCENT_PAREN[ch]
|
1104
|
+
identify_string(lt, @quoted, ch, initial_char)
|
1095
1105
|
end
|
1096
|
-
# if ch !~ /\W/
|
1097
|
-
# ungetc
|
1098
|
-
# next
|
1099
|
-
# end
|
1100
|
-
#@ltype = lt
|
1101
|
-
@quoted = ch unless @quoted = PERCENT_PAREN[ch]
|
1102
|
-
identify_string(lt, @quoted, ch, initial_char)
|
1103
|
-
end
|
1104
1106
|
|
1105
|
-
|
1106
|
-
|
1107
|
+
def identify_number(start)
|
1108
|
+
str = start.dup
|
1107
1109
|
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1110
|
+
if start == "+" or start == "-" or start == ""
|
1111
|
+
start = getc
|
1112
|
+
str << start
|
1113
|
+
end
|
1112
1114
|
|
1113
|
-
|
1115
|
+
@lex_state = EXPR_END
|
1114
1116
|
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
str << ch
|
1119
|
-
match = /[0-9a-f_]/
|
1120
|
-
else
|
1121
|
-
match = /[0-7_]/
|
1122
|
-
end
|
1123
|
-
while ch = getc
|
1124
|
-
if ch !~ match
|
1125
|
-
ungetc
|
1126
|
-
break
|
1127
|
-
else
|
1117
|
+
if start == "0"
|
1118
|
+
if peek(0) == "x"
|
1119
|
+
ch = getc
|
1128
1120
|
str << ch
|
1121
|
+
match = /[0-9a-f_]/
|
1122
|
+
else
|
1123
|
+
match = /[0-7_]/
|
1129
1124
|
end
|
1125
|
+
while ch = getc
|
1126
|
+
if ch !~ match
|
1127
|
+
ungetc
|
1128
|
+
break
|
1129
|
+
else
|
1130
|
+
str << ch
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
return Token(TkINTEGER).set_text(str)
|
1130
1134
|
end
|
1131
|
-
return Token(TkINTEGER).set_text(str)
|
1132
|
-
end
|
1133
1135
|
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1136
|
+
type = TkINTEGER
|
1137
|
+
allow_point = TRUE
|
1138
|
+
allow_e = TRUE
|
1139
|
+
while ch = getc
|
1140
|
+
case ch
|
1141
|
+
when /[0-9_]/
|
1142
|
+
str << ch
|
1143
|
+
|
1144
|
+
when allow_point && "."
|
1145
|
+
type = TkFLOAT
|
1146
|
+
if peek(0) !~ /[0-9]/
|
1147
|
+
ungetc
|
1148
|
+
break
|
1149
|
+
end
|
1150
|
+
str << ch
|
1151
|
+
allow_point = false
|
1152
|
+
|
1153
|
+
when allow_e && "e", allow_e && "E"
|
1154
|
+
str << ch
|
1155
|
+
type = TkFLOAT
|
1156
|
+
if peek(0) =~ /[+-]/
|
1157
|
+
str << getc
|
1158
|
+
end
|
1159
|
+
allow_e = false
|
1160
|
+
allow_point = false
|
1161
|
+
else
|
1162
|
+
ungetc
|
1163
|
+
break
|
1164
|
+
end
|
1162
1165
|
end
|
1166
|
+
Token(type).set_text(str)
|
1163
1167
|
end
|
1164
|
-
Token(type).set_text(str)
|
1165
|
-
end
|
1166
1168
|
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1169
|
+
def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil)
|
1170
|
+
@ltype = ltype
|
1171
|
+
@quoted = quoted
|
1172
|
+
subtype = nil
|
1173
|
+
|
1174
|
+
str = ""
|
1175
|
+
str << initial_char if initial_char
|
1176
|
+
str << (opener||quoted)
|
1177
|
+
|
1178
|
+
nest = 0
|
1179
|
+
begin
|
1180
|
+
while ch = getc
|
1181
|
+
str << ch
|
1182
|
+
if @quoted == ch
|
1183
|
+
if nest == 0
|
1184
|
+
break
|
1185
|
+
else
|
1186
|
+
nest -= 1
|
1187
|
+
end
|
1188
|
+
elsif opener == ch
|
1189
|
+
nest += 1
|
1190
|
+
elsif @ltype != "'" && @ltype != "]" and ch == "#"
|
1191
|
+
ch = getc
|
1192
|
+
if ch == "{"
|
1193
|
+
subtype = true
|
1194
|
+
str << ch << skip_inner_expression
|
1195
|
+
else
|
1196
|
+
ungetc(ch)
|
1197
|
+
end
|
1198
|
+
elsif ch == '\\' #'
|
1199
|
+
str << read_escape
|
1200
|
+
end
|
1201
|
+
end
|
1202
|
+
if @ltype == "/"
|
1203
|
+
if peek(0) =~ /i|o|n|e|s/
|
1204
|
+
str << getc
|
1205
|
+
end
|
1206
|
+
end
|
1207
|
+
if subtype
|
1208
|
+
Token(DLtype2Token[ltype], str)
|
1209
|
+
else
|
1210
|
+
Token(Ltype2Token[ltype], str)
|
1211
|
+
end.set_text(str)
|
1212
|
+
ensure
|
1213
|
+
@ltype = nil
|
1214
|
+
@quoted = nil
|
1215
|
+
@lex_state = EXPR_END
|
1204
1216
|
end
|
1205
|
-
if subtype
|
1206
|
-
Token(DLtype2Token[ltype], str)
|
1207
|
-
else
|
1208
|
-
Token(Ltype2Token[ltype], str)
|
1209
|
-
end.set_text(str)
|
1210
|
-
ensure
|
1211
|
-
@ltype = nil
|
1212
|
-
@quoted = nil
|
1213
|
-
@lex_state = EXPR_END
|
1214
1217
|
end
|
1215
|
-
end
|
1216
1218
|
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1219
|
+
def skip_inner_expression
|
1220
|
+
res = ""
|
1221
|
+
nest = 0
|
1222
|
+
while (ch = getc)
|
1223
|
+
res << ch
|
1224
|
+
if ch == '}'
|
1225
|
+
break if nest.zero?
|
1226
|
+
nest -= 1
|
1227
|
+
elsif ch == '{'
|
1228
|
+
nest += 1
|
1229
|
+
end
|
1227
1230
|
end
|
1231
|
+
res
|
1228
1232
|
end
|
1229
|
-
res
|
1230
|
-
end
|
1231
1233
|
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1234
|
+
def identify_comment
|
1235
|
+
@ltype = "#"
|
1236
|
+
comment = "#"
|
1237
|
+
while ch = getc
|
1238
|
+
if ch == "\\"
|
1239
|
+
ch = getc
|
1240
|
+
if ch == "\n"
|
1241
|
+
ch = " "
|
1242
|
+
else
|
1243
|
+
comment << "\\"
|
1244
|
+
end
|
1240
1245
|
else
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
ungetc
|
1247
|
-
break
|
1246
|
+
if ch == "\n"
|
1247
|
+
@ltype = nil
|
1248
|
+
ungetc
|
1249
|
+
break
|
1250
|
+
end
|
1248
1251
|
end
|
1252
|
+
comment << ch
|
1249
1253
|
end
|
1250
|
-
comment
|
1254
|
+
return Token(TkCOMMENT).set_text(comment)
|
1251
1255
|
end
|
1252
|
-
return Token(TkCOMMENT).set_text(comment)
|
1253
|
-
end
|
1254
1256
|
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1257
|
+
def read_escape
|
1258
|
+
res = ""
|
1259
|
+
case ch = getc
|
1260
|
+
when /[0-7]/
|
1261
|
+
ungetc ch
|
1262
|
+
3.times do
|
1263
|
+
case ch = getc
|
1264
|
+
when /[0-7]/
|
1265
|
+
when nil
|
1266
|
+
break
|
1267
|
+
else
|
1268
|
+
ungetc
|
1269
|
+
break
|
1270
|
+
end
|
1271
|
+
res << ch
|
1272
|
+
end
|
1271
1273
|
|
1272
|
-
|
1273
|
-
res << ch
|
1274
|
-
2.times do
|
1275
|
-
case ch = getc
|
1276
|
-
when /[0-9a-fA-F]/
|
1277
|
-
when nil
|
1278
|
-
break
|
1279
|
-
else
|
1280
|
-
ungetc
|
1281
|
-
break
|
1282
|
-
end
|
1274
|
+
when "x"
|
1283
1275
|
res << ch
|
1284
|
-
|
1276
|
+
2.times do
|
1277
|
+
case ch = getc
|
1278
|
+
when /[0-9a-fA-F]/
|
1279
|
+
when nil
|
1280
|
+
break
|
1281
|
+
else
|
1282
|
+
ungetc
|
1283
|
+
break
|
1284
|
+
end
|
1285
|
+
res << ch
|
1286
|
+
end
|
1285
1287
|
|
1286
|
-
|
1287
|
-
res << ch
|
1288
|
-
if (ch = getc) != '-'
|
1289
|
-
ungetc
|
1290
|
-
else
|
1288
|
+
when "M"
|
1291
1289
|
res << ch
|
1292
|
-
|
1293
|
-
|
1294
|
-
res << read_escape
|
1290
|
+
if (ch = getc) != '-'
|
1291
|
+
ungetc
|
1295
1292
|
else
|
1296
1293
|
res << ch
|
1297
|
-
|
1298
|
-
|
1294
|
+
if (ch = getc) == "\\" #"
|
1295
|
+
res << ch
|
1296
|
+
res << read_escape
|
1297
|
+
else
|
1298
|
+
res << ch
|
1299
|
+
end
|
1300
|
+
end
|
1299
1301
|
|
1300
|
-
|
1301
|
-
res << ch
|
1302
|
-
if ch == "C" and (ch = getc) != "-"
|
1303
|
-
ungetc
|
1304
|
-
else
|
1302
|
+
when "C", "c" #, "^"
|
1305
1303
|
res << ch
|
1306
|
-
if (ch = getc)
|
1307
|
-
|
1308
|
-
res << read_escape
|
1304
|
+
if ch == "C" and (ch = getc) != "-"
|
1305
|
+
ungetc
|
1309
1306
|
else
|
1310
1307
|
res << ch
|
1308
|
+
if (ch = getc) == "\\" #"
|
1309
|
+
res << ch
|
1310
|
+
res << read_escape
|
1311
|
+
else
|
1312
|
+
res << ch
|
1313
|
+
end
|
1311
1314
|
end
|
1315
|
+
else
|
1316
|
+
res << ch
|
1312
1317
|
end
|
1313
|
-
|
1314
|
-
res << ch
|
1318
|
+
res
|
1315
1319
|
end
|
1316
|
-
res
|
1317
1320
|
end
|
1318
|
-
end
|
1321
|
+
end
|