irb 1.1.0.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +55 -0
  5. data/Rakefile +10 -0
  6. data/bin/console +6 -0
  7. data/bin/setup +6 -0
  8. data/doc/irb/irb-tools.rd.ja +184 -0
  9. data/doc/irb/irb.rd.ja +411 -0
  10. data/exe/irb +11 -0
  11. data/irb.gemspec +84 -0
  12. data/lib/irb.rb +870 -0
  13. data/lib/irb/cmd/chws.rb +34 -0
  14. data/lib/irb/cmd/fork.rb +39 -0
  15. data/lib/irb/cmd/help.rb +46 -0
  16. data/lib/irb/cmd/load.rb +67 -0
  17. data/lib/irb/cmd/nop.rb +39 -0
  18. data/lib/irb/cmd/pushws.rb +41 -0
  19. data/lib/irb/cmd/subirb.rb +43 -0
  20. data/lib/irb/color.rb +233 -0
  21. data/lib/irb/completion.rb +339 -0
  22. data/lib/irb/context.rb +458 -0
  23. data/lib/irb/ext/change-ws.rb +46 -0
  24. data/lib/irb/ext/history.rb +157 -0
  25. data/lib/irb/ext/loader.rb +129 -0
  26. data/lib/irb/ext/multi-irb.rb +265 -0
  27. data/lib/irb/ext/save-history.rb +117 -0
  28. data/lib/irb/ext/tracer.rb +72 -0
  29. data/lib/irb/ext/use-loader.rb +77 -0
  30. data/lib/irb/ext/workspaces.rb +67 -0
  31. data/lib/irb/extend-command.rb +328 -0
  32. data/lib/irb/frame.rb +81 -0
  33. data/lib/irb/help.rb +37 -0
  34. data/lib/irb/init.rb +312 -0
  35. data/lib/irb/input-method.rb +298 -0
  36. data/lib/irb/inspector.rb +142 -0
  37. data/lib/irb/lc/.document +4 -0
  38. data/lib/irb/lc/error.rb +32 -0
  39. data/lib/irb/lc/help-message +52 -0
  40. data/lib/irb/lc/ja/encoding_aliases.rb +11 -0
  41. data/lib/irb/lc/ja/error.rb +31 -0
  42. data/lib/irb/lc/ja/help-message +55 -0
  43. data/lib/irb/locale.rb +182 -0
  44. data/lib/irb/magic-file.rb +38 -0
  45. data/lib/irb/notifier.rb +232 -0
  46. data/lib/irb/output-method.rb +92 -0
  47. data/lib/irb/ruby-lex.rb +499 -0
  48. data/lib/irb/ruby_logo.aa +38 -0
  49. data/lib/irb/slex.rb +282 -0
  50. data/lib/irb/src_encoding.rb +7 -0
  51. data/lib/irb/version.rb +17 -0
  52. data/lib/irb/workspace.rb +181 -0
  53. data/lib/irb/ws-for-case-2.rb +15 -0
  54. data/lib/irb/xmp.rb +170 -0
  55. data/man/irb.1 +207 -0
  56. metadata +140 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: false
2
+ module IRB
3
+ class << (MagicFile = Object.new)
4
+ # see parser_magic_comment in parse.y
5
+ ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
6
+
7
+ def open(path)
8
+ io = File.open(path, 'rb')
9
+ line = io.gets
10
+ line = io.gets if line[0,2] == "#!"
11
+ encoding = detect_encoding(line)
12
+ internal_encoding = encoding
13
+ encoding ||= IRB.default_src_encoding
14
+ io.rewind
15
+ io.set_encoding(encoding, internal_encoding)
16
+
17
+ if block_given?
18
+ begin
19
+ return (yield io)
20
+ ensure
21
+ io.close
22
+ end
23
+ else
24
+ return io
25
+ end
26
+ end
27
+
28
+ private
29
+ def detect_encoding(line)
30
+ return unless line[0] == ?#
31
+ line = line[1..-1]
32
+ line = $1 if line[/-\*-\s*(.*?)\s*-*-$/]
33
+ return nil unless ENCODING_SPEC_RE =~ line
34
+ encoding = $1
35
+ return encoding.sub(/-(?:mac|dos|unix)/i, '')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # notifier.rb - output methods used by irb
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require "e2mmap"
14
+ require_relative "output-method"
15
+
16
+ module IRB
17
+ # An output formatter used internally by the lexer.
18
+ module Notifier
19
+ extend Exception2MessageMapper
20
+ def_exception :ErrUndefinedNotifier,
21
+ "undefined notifier level: %d is specified"
22
+ def_exception :ErrUnrecognizedLevel,
23
+ "unrecognized notifier level: %s is specified"
24
+
25
+ # Define a new Notifier output source, returning a new CompositeNotifier
26
+ # with the given +prefix+ and +output_method+.
27
+ #
28
+ # The optional +prefix+ will be appended to all objects being inspected
29
+ # during output, using the given +output_method+ as the output source. If
30
+ # no +output_method+ is given, StdioOutputMethod will be used, and all
31
+ # expressions will be sent directly to STDOUT without any additional
32
+ # formatting.
33
+ def def_notifier(prefix = "", output_method = StdioOutputMethod.new)
34
+ CompositeNotifier.new(prefix, output_method)
35
+ end
36
+ module_function :def_notifier
37
+
38
+ # An abstract class, or superclass, for CompositeNotifier and
39
+ # LeveledNotifier to inherit. It provides several wrapper methods for the
40
+ # OutputMethod object used by the Notifier.
41
+ class AbstractNotifier
42
+ # Creates a new Notifier object
43
+ def initialize(prefix, base_notifier)
44
+ @prefix = prefix
45
+ @base_notifier = base_notifier
46
+ end
47
+
48
+ # The +prefix+ for this Notifier, which is appended to all objects being
49
+ # inspected during output.
50
+ attr_reader :prefix
51
+
52
+ # A wrapper method used to determine whether notifications are enabled.
53
+ #
54
+ # Defaults to +true+.
55
+ def notify?
56
+ true
57
+ end
58
+
59
+ # See OutputMethod#print for more detail.
60
+ def print(*opts)
61
+ @base_notifier.print prefix, *opts if notify?
62
+ end
63
+
64
+ # See OutputMethod#printn for more detail.
65
+ def printn(*opts)
66
+ @base_notifier.printn prefix, *opts if notify?
67
+ end
68
+
69
+ # See OutputMethod#printf for more detail.
70
+ def printf(format, *opts)
71
+ @base_notifier.printf(prefix + format, *opts) if notify?
72
+ end
73
+
74
+ # See OutputMethod#puts for more detail.
75
+ def puts(*objs)
76
+ if notify?
77
+ @base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s})
78
+ end
79
+ end
80
+
81
+ # Same as #ppx, except it uses the #prefix given during object
82
+ # initialization.
83
+ # See OutputMethod#ppx for more detail.
84
+ def pp(*objs)
85
+ if notify?
86
+ @base_notifier.ppx @prefix, *objs
87
+ end
88
+ end
89
+
90
+ # Same as #pp, except it concatenates the given +prefix+ with the #prefix
91
+ # given during object initialization.
92
+ #
93
+ # See OutputMethod#ppx for more detail.
94
+ def ppx(prefix, *objs)
95
+ if notify?
96
+ @base_notifier.ppx @prefix+prefix, *objs
97
+ end
98
+ end
99
+
100
+ # Execute the given block if notifications are enabled.
101
+ def exec_if
102
+ yield(@base_notifier) if notify?
103
+ end
104
+ end
105
+
106
+ # A class that can be used to create a group of notifier objects with the
107
+ # intent of representing a leveled notification system for irb.
108
+ #
109
+ # This class will allow you to generate other notifiers, and assign them
110
+ # the appropriate level for output.
111
+ #
112
+ # The Notifier class provides a class-method Notifier.def_notifier to
113
+ # create a new composite notifier. Using the first composite notifier
114
+ # object you create, sibling notifiers can be initialized with
115
+ # #def_notifier.
116
+ class CompositeNotifier < AbstractNotifier
117
+ # Create a new composite notifier object with the given +prefix+, and
118
+ # +base_notifier+ to use for output.
119
+ def initialize(prefix, base_notifier)
120
+ super
121
+
122
+ @notifiers = [D_NOMSG]
123
+ @level_notifier = D_NOMSG
124
+ end
125
+
126
+ # List of notifiers in the group
127
+ attr_reader :notifiers
128
+
129
+ # Creates a new LeveledNotifier in the composite #notifiers group.
130
+ #
131
+ # The given +prefix+ will be assigned to the notifier, and +level+ will
132
+ # be used as the index of the #notifiers Array.
133
+ #
134
+ # This method returns the newly created instance.
135
+ def def_notifier(level, prefix = "")
136
+ notifier = LeveledNotifier.new(self, level, prefix)
137
+ @notifiers[level] = notifier
138
+ notifier
139
+ end
140
+
141
+ # Returns the leveled notifier for this object
142
+ attr_reader :level_notifier
143
+ alias level level_notifier
144
+
145
+ # Sets the leveled notifier for this object.
146
+ #
147
+ # When the given +value+ is an instance of AbstractNotifier,
148
+ # #level_notifier is set to the given object.
149
+ #
150
+ # When an Integer is given, #level_notifier is set to the notifier at the
151
+ # index +value+ in the #notifiers Array.
152
+ #
153
+ # If no notifier exists at the index +value+ in the #notifiers Array, an
154
+ # ErrUndefinedNotifier exception is raised.
155
+ #
156
+ # An ErrUnrecognizedLevel exception is raised if the given +value+ is not
157
+ # found in the existing #notifiers Array, or an instance of
158
+ # AbstractNotifier
159
+ def level_notifier=(value)
160
+ case value
161
+ when AbstractNotifier
162
+ @level_notifier = value
163
+ when Integer
164
+ l = @notifiers[value]
165
+ Notifier.Raise ErrUndefinedNotifier, value unless l
166
+ @level_notifier = l
167
+ else
168
+ Notifier.Raise ErrUnrecognizedLevel, value unless l
169
+ end
170
+ end
171
+
172
+ alias level= level_notifier=
173
+ end
174
+
175
+ # A leveled notifier is comparable to the composite group from
176
+ # CompositeNotifier#notifiers.
177
+ class LeveledNotifier < AbstractNotifier
178
+ include Comparable
179
+
180
+ # Create a new leveled notifier with the given +base+, and +prefix+ to
181
+ # send to AbstractNotifier.new
182
+ #
183
+ # The given +level+ is used to compare other leveled notifiers in the
184
+ # CompositeNotifier group to determine whether or not to output
185
+ # notifications.
186
+ def initialize(base, level, prefix)
187
+ super(prefix, base)
188
+
189
+ @level = level
190
+ end
191
+
192
+ # The current level of this notifier object
193
+ attr_reader :level
194
+
195
+ # Compares the level of this notifier object with the given +other+
196
+ # notifier.
197
+ #
198
+ # See the Comparable module for more information.
199
+ def <=>(other)
200
+ @level <=> other.level
201
+ end
202
+
203
+ # Whether to output messages to the output method, depending on the level
204
+ # of this notifier object.
205
+ def notify?
206
+ @base_notifier.level >= self
207
+ end
208
+ end
209
+
210
+ # NoMsgNotifier is a LeveledNotifier that's used as the default notifier
211
+ # when creating a new CompositeNotifier.
212
+ #
213
+ # This notifier is used as the +zero+ index, or level +0+, for
214
+ # CompositeNotifier#notifiers, and will not output messages of any sort.
215
+ class NoMsgNotifier < LeveledNotifier
216
+ # Creates a new notifier that should not be used to output messages.
217
+ def initialize
218
+ @base_notifier = nil
219
+ @level = 0
220
+ @prefix = ""
221
+ end
222
+
223
+ # Ensures notifications are ignored, see AbstractNotifier#notify? for
224
+ # more information.
225
+ def notify?
226
+ false
227
+ end
228
+ end
229
+
230
+ D_NOMSG = NoMsgNotifier.new # :nodoc:
231
+ end
232
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # output-method.rb - output methods used by irb
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require "e2mmap"
14
+
15
+ module IRB
16
+ # An abstract output class for IO in irb. This is mainly used internally by
17
+ # IRB::Notifier. You can define your own output method to use with Irb.new,
18
+ # or Context.new
19
+ class OutputMethod
20
+ extend Exception2MessageMapper
21
+ def_exception :NotImplementedError, "Need to define `%s'"
22
+
23
+
24
+ # Open this method to implement your own output method, raises a
25
+ # NotImplementedError if you don't define #print in your own class.
26
+ def print(*opts)
27
+ OutputMethod.Raise NotImplementedError, "print"
28
+ end
29
+
30
+ # Prints the given +opts+, with a newline delimiter.
31
+ def printn(*opts)
32
+ print opts.join(" "), "\n"
33
+ end
34
+
35
+ # Extends IO#printf to format the given +opts+ for Kernel#sprintf using
36
+ # #parse_printf_format
37
+ def printf(format, *opts)
38
+ if /(%*)%I/ =~ format
39
+ format, opts = parse_printf_format(format, opts)
40
+ end
41
+ print sprintf(format, *opts)
42
+ end
43
+
44
+ # Returns an array of the given +format+ and +opts+ to be used by
45
+ # Kernel#sprintf, if there was a successful Regexp match in the given
46
+ # +format+ from #printf
47
+ #
48
+ # %
49
+ # <flag> [#0- +]
50
+ # <minimum field width> (\*|\*[1-9][0-9]*\$|[1-9][0-9]*)
51
+ # <precision>.(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)?
52
+ # #<length modifier>(hh|h|l|ll|L|q|j|z|t)
53
+ # <conversion specifier>[diouxXeEfgGcsb%]
54
+ def parse_printf_format(format, opts)
55
+ return format, opts if $1.size % 2 == 1
56
+ end
57
+
58
+ # Calls #print on each element in the given +objs+, followed by a newline
59
+ # character.
60
+ def puts(*objs)
61
+ for obj in objs
62
+ print(*obj)
63
+ print "\n"
64
+ end
65
+ end
66
+
67
+ # Prints the given +objs+ calling Object#inspect on each.
68
+ #
69
+ # See #puts for more detail.
70
+ def pp(*objs)
71
+ puts(*objs.collect{|obj| obj.inspect})
72
+ end
73
+
74
+ # Prints the given +objs+ calling Object#inspect on each and appending the
75
+ # given +prefix+.
76
+ #
77
+ # See #puts for more detail.
78
+ def ppx(prefix, *objs)
79
+ puts(*objs.collect{|obj| prefix+obj.inspect})
80
+ end
81
+
82
+ end
83
+
84
+ # A standard output printer
85
+ class StdioOutputMethod < OutputMethod
86
+ # Prints the given +opts+ to standard output, see IO#print for more
87
+ # information.
88
+ def print(*opts)
89
+ STDOUT.print(*opts)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,499 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # irb/ruby-lex.rb - ruby lexcal analyzer
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require "e2mmap"
14
+ require "ripper"
15
+
16
+ # :stopdoc:
17
+ class RubyLex
18
+
19
+ extend Exception2MessageMapper
20
+ def_exception(:TerminateLineInput, "Terminate Line Input")
21
+
22
+ def initialize
23
+ @exp_line_no = @line_no = 1
24
+ @indent = 0
25
+ @continue = false
26
+ @line = ""
27
+ @prompt = nil
28
+ end
29
+
30
+ # io functions
31
+ def set_input(io, p = nil, &block)
32
+ @io = io
33
+ if @io.respond_to?(:check_termination)
34
+ @io.check_termination do |code|
35
+ code.gsub!(/\s*\z/, '').concat("\n")
36
+ ltype, indent, continue, code_block_open = check_state(code)
37
+ if ltype or indent > 0 or continue or code_block_open
38
+ false
39
+ else
40
+ true
41
+ end
42
+ end
43
+ end
44
+ if @io.respond_to?(:dynamic_prompt)
45
+ @io.dynamic_prompt do |lines|
46
+ lines << '' if lines.empty?
47
+ result = []
48
+ lines.each_index { |i|
49
+ c = lines[0..i].map{ |l| l + "\n" }.join
50
+ ltype, indent, continue, code_block_open = check_state(c)
51
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i)
52
+ }
53
+ result
54
+ end
55
+ end
56
+ if p.respond_to?(:call)
57
+ @input = p
58
+ elsif block_given?
59
+ @input = block
60
+ else
61
+ @input = Proc.new{@io.gets}
62
+ end
63
+ end
64
+
65
+ def set_prompt(p = nil, &block)
66
+ p = block if block_given?
67
+ if p.respond_to?(:call)
68
+ @prompt = p
69
+ else
70
+ @prompt = Proc.new{print p}
71
+ end
72
+ end
73
+
74
+ def ripper_lex_without_warning(code)
75
+ verbose, $VERBOSE = $VERBOSE, nil
76
+ tokens = Ripper.lex(code)
77
+ $VERBOSE = verbose
78
+ tokens
79
+ end
80
+
81
+ def set_auto_indent(context)
82
+ if @io.respond_to?(:auto_indent) and context.auto_indent_mode
83
+ @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
84
+ if is_newline
85
+ md = lines[line_index - 1].match(/(\A +)/)
86
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
87
+ @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n"))
88
+ depth_difference = check_newline_depth_difference
89
+ prev_spaces + depth_difference * 2
90
+ else
91
+ code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
92
+ last_line = lines[line_index]&.byteslice(0, byte_pointer)
93
+ code += last_line if last_line
94
+ @tokens = ripper_lex_without_warning(code)
95
+ corresponding_token_depth = check_corresponding_token_depth
96
+ if corresponding_token_depth
97
+ corresponding_token_depth
98
+ else
99
+ nil
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def check_state(code)
107
+ @tokens = ripper_lex_without_warning(code)
108
+ ltype = process_literal_type
109
+ indent = process_nesting_level
110
+ continue = process_continue
111
+ code_block_open = check_code_block(code)
112
+ [ltype, indent, continue, code_block_open]
113
+ end
114
+
115
+ def prompt
116
+ if @prompt
117
+ @prompt.call(@ltype, @indent, @continue, @line_no)
118
+ end
119
+ end
120
+
121
+ def initialize_input
122
+ @ltype = nil
123
+ @indent = 0
124
+ @continue = false
125
+ @line = ""
126
+ @exp_line_no = @line_no
127
+ @code_block_open = false
128
+ end
129
+
130
+ def each_top_level_statement
131
+ initialize_input
132
+ catch(:TERM_INPUT) do
133
+ loop do
134
+ begin
135
+ prompt
136
+ unless l = lex
137
+ throw :TERM_INPUT if @line == ''
138
+ else
139
+ @line_no += l.count("\n")
140
+ next if l == "\n"
141
+ @line.concat l
142
+ if @code_block_open or @ltype or @continue or @indent > 0
143
+ next
144
+ end
145
+ end
146
+ if @line != "\n"
147
+ @line.force_encoding(@io.encoding)
148
+ yield @line, @exp_line_no
149
+ end
150
+ break if @io.eof?
151
+ @line = ''
152
+ @exp_line_no = @line_no
153
+
154
+ @indent = 0
155
+ rescue TerminateLineInput
156
+ initialize_input
157
+ prompt
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ def lex
164
+ line = @input.call
165
+ if @io.respond_to?(:check_termination)
166
+ return line # multiline
167
+ end
168
+ code = @line + (line.nil? ? '' : line)
169
+ code.gsub!(/\s*\z/, '').concat("\n")
170
+ @tokens = ripper_lex_without_warning(code)
171
+ @continue = process_continue
172
+ @code_block_open = check_code_block(code)
173
+ @indent = process_nesting_level
174
+ @ltype = process_literal_type
175
+ line
176
+ end
177
+
178
+ def process_continue
179
+ # last token is always newline
180
+ if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end
181
+ # end of regexp literal
182
+ return false
183
+ elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon
184
+ return false
185
+ elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2])
186
+ return false
187
+ elsif @tokens.size >= 3 and @tokens[-3][1] == :on_symbeg and @tokens[-2][1] == :on_ivar
188
+ # This is for :@a or :@1 because :@1 ends with EXPR_FNAME
189
+ return false
190
+ elsif @tokens.size >= 2 and @tokens[-2][1] == :on_ivar and @tokens[-2][2] =~ /\A@\d+\z/
191
+ # This is for @1
192
+ return false
193
+ elsif @tokens.size >= 2 and @tokens[-2][1] == :on_cvar and @tokens[-1][1] == :on_int
194
+ # This is for @@1 or :@@1 and ends with on_int because it's syntax error
195
+ return false
196
+ elsif !@tokens.empty? and @tokens.last[2] == "\\\n"
197
+ return true
198
+ elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n"
199
+ return false
200
+ elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
201
+ # end of literal except for regexp
202
+ return true
203
+ end
204
+ false
205
+ end
206
+
207
+ def check_code_block(code)
208
+ return true if @tokens.empty?
209
+ if @tokens.last[1] == :on_heredoc_beg
210
+ return true
211
+ end
212
+
213
+ begin # check if parser error are available
214
+ verbose, $VERBOSE = $VERBOSE, nil
215
+ case RUBY_ENGINE
216
+ when 'jruby'
217
+ JRuby.compile_ir(code)
218
+ else
219
+ RubyVM::InstructionSequence.compile(code)
220
+ end
221
+ rescue SyntaxError => e
222
+ case e.message
223
+ when /unterminated (?:string|regexp) meets end of file/
224
+ # "unterminated regexp meets end of file"
225
+ #
226
+ # example:
227
+ # /
228
+ #
229
+ # "unterminated string meets end of file"
230
+ #
231
+ # example:
232
+ # '
233
+ return true
234
+ when /syntax error, unexpected end-of-input/
235
+ # "syntax error, unexpected end-of-input, expecting keyword_end"
236
+ #
237
+ # example:
238
+ # if ture
239
+ # hoge
240
+ # if false
241
+ # fuga
242
+ # end
243
+ return true
244
+ when /syntax error, unexpected keyword_end/
245
+ # "syntax error, unexpected keyword_end"
246
+ #
247
+ # example:
248
+ # if (
249
+ # end
250
+ #
251
+ # example:
252
+ # end
253
+ return false
254
+ when /syntax error, unexpected '\.'/
255
+ # "syntax error, unexpected '.'"
256
+ #
257
+ # example:
258
+ # .
259
+ return false
260
+ when /unexpected tREGEXP_BEG/
261
+ # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
262
+ #
263
+ # example:
264
+ # method / f /
265
+ return false
266
+ when /numbered parameter outside block/
267
+ # "numbered parameter outside block"
268
+ #
269
+ # example:
270
+ # :@1
271
+ return false
272
+ end
273
+ ensure
274
+ $VERBOSE = verbose
275
+ end
276
+
277
+ if defined?(Ripper::EXPR_BEG)
278
+ last_lex_state = @tokens.last[3]
279
+ if last_lex_state.allbits?(Ripper::EXPR_BEG)
280
+ return false
281
+ elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
282
+ return true
283
+ elsif last_lex_state.allbits?(Ripper::EXPR_CLASS)
284
+ return true
285
+ elsif last_lex_state.allbits?(Ripper::EXPR_FNAME)
286
+ return true
287
+ elsif last_lex_state.allbits?(Ripper::EXPR_VALUE)
288
+ return true
289
+ elsif last_lex_state.allbits?(Ripper::EXPR_ARG)
290
+ return false
291
+ end
292
+ end
293
+
294
+ false
295
+ end
296
+
297
+ def process_nesting_level
298
+ indent = 0
299
+ @tokens.each_with_index { |t, index|
300
+ case t[1]
301
+ when :on_lbracket, :on_lbrace, :on_lparen
302
+ indent += 1
303
+ when :on_rbracket, :on_rbrace, :on_rparen
304
+ indent -= 1
305
+ when :on_kw
306
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
307
+ case t[2]
308
+ when 'do'
309
+ if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_CMDARG)
310
+ # method_with_bock do; end
311
+ indent += 1
312
+ else
313
+ # while cond do; end # also "until" or "for"
314
+ # This "do" doesn't increment indent because "while" already
315
+ # incremented.
316
+ end
317
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
318
+ indent += 1
319
+ when 'if', 'unless', 'while', 'until'
320
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
321
+ indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL)
322
+ when 'end'
323
+ indent -= 1
324
+ end
325
+ end
326
+ # percent literals are not indented
327
+ }
328
+ indent
329
+ end
330
+
331
+ def check_newline_depth_difference
332
+ depth_difference = 0
333
+ @tokens.each_with_index do |t, index|
334
+ case t[1]
335
+ when :on_ignored_nl, :on_nl
336
+ if index != (@tokens.size - 1)
337
+ depth_difference = 0
338
+ end
339
+ next
340
+ when :on_sp
341
+ next
342
+ end
343
+ case t[1]
344
+ when :on_lbracket, :on_lbrace, :on_lparen
345
+ depth_difference += 1
346
+ when :on_rbracket, :on_rbrace, :on_rparen
347
+ depth_difference -= 1
348
+ when :on_kw
349
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
350
+ case t[2]
351
+ when 'do'
352
+ if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_CMDARG)
353
+ # method_with_bock do; end
354
+ depth_difference += 1
355
+ else
356
+ # while cond do; end # also "until" or "for"
357
+ # This "do" doesn't increment indent because "while" already
358
+ # incremented.
359
+ end
360
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
361
+ depth_difference += 1
362
+ when 'if', 'unless', 'while', 'until'
363
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
364
+ unless t[3].allbits?(Ripper::EXPR_LABEL)
365
+ depth_difference += 1
366
+ end
367
+ when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
368
+ depth_difference += 1
369
+ end
370
+ end
371
+ end
372
+ depth_difference
373
+ end
374
+
375
+ def check_corresponding_token_depth
376
+ corresponding_token_depth = nil
377
+ is_first_spaces_of_line = true
378
+ is_first_printable_of_line = true
379
+ spaces_of_nest = []
380
+ spaces_at_line_head = 0
381
+ @tokens.each_with_index do |t, index|
382
+ corresponding_token_depth = nil
383
+ case t[1]
384
+ when :on_ignored_nl, :on_nl
385
+ spaces_at_line_head = 0
386
+ is_first_spaces_of_line = true
387
+ is_first_printable_of_line = true
388
+ next
389
+ when :on_sp
390
+ spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
391
+ is_first_spaces_of_line = false
392
+ next
393
+ end
394
+ case t[1]
395
+ when :on_lbracket, :on_lbrace, :on_lparen
396
+ spaces_of_nest.push(spaces_at_line_head)
397
+ when :on_rbracket, :on_rbrace, :on_rparen
398
+ if is_first_printable_of_line
399
+ corresponding_token_depth = spaces_of_nest.pop
400
+ else
401
+ spaces_of_nest.pop
402
+ corresponding_token_depth = nil
403
+ end
404
+ when :on_kw
405
+ next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
406
+ case t[2]
407
+ when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
408
+ spaces_of_nest.push(spaces_at_line_head)
409
+ when 'if', 'unless', 'while', 'until'
410
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
411
+ unless t[3].allbits?(Ripper::EXPR_LABEL)
412
+ spaces_of_nest.push(spaces_at_line_head)
413
+ end
414
+ when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
415
+ corresponding_token_depth = spaces_of_nest.last
416
+ when 'end'
417
+ if is_first_printable_of_line
418
+ corresponding_token_depth = spaces_of_nest.pop
419
+ else
420
+ spaces_of_nest.pop
421
+ corresponding_token_depth = nil
422
+ end
423
+ end
424
+ end
425
+ is_first_spaces_of_line = false
426
+ is_first_printable_of_line = false
427
+ end
428
+ corresponding_token_depth
429
+ end
430
+
431
+ def check_string_literal
432
+ i = 0
433
+ start_token = []
434
+ end_type = []
435
+ while i < @tokens.size
436
+ t = @tokens[i]
437
+ case t[1]
438
+ when :on_tstring_beg
439
+ start_token << t
440
+ end_type << [:on_tstring_end, :on_label_end]
441
+ when :on_regexp_beg
442
+ start_token << t
443
+ end_type << :on_regexp_end
444
+ when :on_symbeg
445
+ acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
446
+ if (i + 1) < @tokens.size and acceptable_single_tokens.all?{ |t| @tokens[i + 1][1] != t }
447
+ start_token << t
448
+ end_type << :on_tstring_end
449
+ end
450
+ when :on_backtick
451
+ start_token << t
452
+ end_type << :on_tstring_end
453
+ when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg
454
+ start_token << t
455
+ end_type << :on_tstring_end
456
+ when :on_heredoc_beg
457
+ start_token << t
458
+ end_type << :on_heredoc_end
459
+ when *end_type.last
460
+ start_token.pop
461
+ end_type.pop
462
+ end
463
+ i += 1
464
+ end
465
+ start_token.last.nil? ? '' : start_token.last
466
+ end
467
+
468
+ def process_literal_type
469
+ start_token = check_string_literal
470
+ case start_token[1]
471
+ when :on_tstring_beg
472
+ case start_token[2]
473
+ when ?" then ?"
474
+ when /^%.$/ then ?"
475
+ when /^%Q.$/ then ?"
476
+ when ?' then ?'
477
+ when /^%q.$/ then ?'
478
+ end
479
+ when :on_regexp_beg then ?/
480
+ when :on_symbeg then ?:
481
+ when :on_backtick then ?`
482
+ when :on_qwords_beg then ?]
483
+ when :on_words_beg then ?]
484
+ when :on_qsymbols_beg then ?]
485
+ when :on_symbols_beg then ?]
486
+ when :on_heredoc_beg
487
+ start_token[2] =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
488
+ case $1
489
+ when ?" then ?"
490
+ when ?' then ?'
491
+ when ?` then ?`
492
+ else ?"
493
+ end
494
+ else
495
+ nil
496
+ end
497
+ end
498
+ end
499
+ # :startdoc: