irb 1.1.0.pre.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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: