irb 1.6.4 → 1.7.1
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.
- checksums.yaml +4 -4
- data/lib/irb/cmd/help.rb +12 -46
- data/lib/irb/cmd/irb_info.rb +14 -18
- data/lib/irb/cmd/ls.rb +5 -2
- data/lib/irb/cmd/nop.rb +4 -8
- data/lib/irb/cmd/show_doc.rb +48 -0
- data/lib/irb/cmd/show_source.rb +7 -6
- data/lib/irb/completion.rb +2 -2
- data/lib/irb/context.rb +19 -16
- data/lib/irb/ext/loader.rb +2 -0
- data/lib/irb/ext/tracer.rb +1 -1
- data/lib/irb/extend-command.rb +6 -2
- data/lib/irb/help.rb +1 -3
- data/lib/irb/input-method.rb +4 -3
- data/lib/irb/locale.rb +10 -43
- data/lib/irb/nesting_parser.rb +227 -0
- data/lib/irb/ruby-lex.rb +266 -559
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +25 -31
- metadata +5 -6
- data/lib/irb/cmd/fork.rb +0 -34
- data/lib/irb/lc/ja/encoding_aliases.rb +0 -13
- data/lib/irb/magic-file.rb +0 -38
@@ -0,0 +1,227 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module IRB
|
3
|
+
module NestingParser
|
4
|
+
IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
|
5
|
+
|
6
|
+
# Scan each token and call the given block with array of token and other information for parsing
|
7
|
+
def self.scan_opens(tokens)
|
8
|
+
opens = []
|
9
|
+
pending_heredocs = []
|
10
|
+
first_token_on_line = true
|
11
|
+
tokens.each do |t|
|
12
|
+
skip = false
|
13
|
+
last_tok, state, args = opens.last
|
14
|
+
case state
|
15
|
+
when :in_unquoted_symbol
|
16
|
+
unless IGNORE_TOKENS.include?(t.event)
|
17
|
+
opens.pop
|
18
|
+
skip = true
|
19
|
+
end
|
20
|
+
when :in_lambda_head
|
21
|
+
opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
|
22
|
+
when :in_method_head
|
23
|
+
unless IGNORE_TOKENS.include?(t.event)
|
24
|
+
next_args = []
|
25
|
+
body = nil
|
26
|
+
if args.include?(:receiver)
|
27
|
+
case t.event
|
28
|
+
when :on_lparen, :on_ivar, :on_gvar, :on_cvar
|
29
|
+
# def (receiver). | def @ivar. | def $gvar. | def @@cvar.
|
30
|
+
next_args << :dot
|
31
|
+
when :on_kw
|
32
|
+
case t.tok
|
33
|
+
when 'self', 'true', 'false', 'nil'
|
34
|
+
# def self(arg) | def self.
|
35
|
+
next_args.push(:arg, :dot)
|
36
|
+
else
|
37
|
+
# def if(arg)
|
38
|
+
skip = true
|
39
|
+
next_args << :arg
|
40
|
+
end
|
41
|
+
when :on_op, :on_backtick
|
42
|
+
# def +(arg)
|
43
|
+
skip = true
|
44
|
+
next_args << :arg
|
45
|
+
when :on_ident, :on_const
|
46
|
+
# def a(arg) | def a.
|
47
|
+
next_args.push(:arg, :dot)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if args.include?(:dot)
|
51
|
+
# def receiver.name
|
52
|
+
next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
|
53
|
+
end
|
54
|
+
if args.include?(:name)
|
55
|
+
if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
|
56
|
+
# def name(arg) | def receiver.name(arg)
|
57
|
+
next_args << :arg
|
58
|
+
skip = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if args.include?(:arg)
|
62
|
+
case t.event
|
63
|
+
when :on_nl, :on_semicolon
|
64
|
+
# def recever.f;
|
65
|
+
body = :normal
|
66
|
+
when :on_lparen
|
67
|
+
# def recever.f()
|
68
|
+
next_args << :eq
|
69
|
+
else
|
70
|
+
if t.event == :on_op && t.tok == '='
|
71
|
+
# def receiver.f =
|
72
|
+
body = :oneliner
|
73
|
+
else
|
74
|
+
# def recever.f arg
|
75
|
+
next_args << :arg_without_paren
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if args.include?(:eq)
|
80
|
+
if t.event == :on_op && t.tok == '='
|
81
|
+
body = :oneliner
|
82
|
+
else
|
83
|
+
body = :normal
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if args.include?(:arg_without_paren)
|
87
|
+
if %i[on_semicolon on_nl].include?(t.event)
|
88
|
+
# def f a;
|
89
|
+
body = :normal
|
90
|
+
else
|
91
|
+
# def f a, b
|
92
|
+
next_args << :arg_without_paren
|
93
|
+
end
|
94
|
+
end
|
95
|
+
if body == :oneliner
|
96
|
+
opens.pop
|
97
|
+
elsif body
|
98
|
+
opens[-1] = [last_tok, nil]
|
99
|
+
else
|
100
|
+
opens[-1] = [last_tok, :in_method_head, next_args]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
when :in_for_while_until_condition
|
104
|
+
if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
|
105
|
+
skip = true if t.event == :on_kw && t.tok == 'do'
|
106
|
+
opens[-1] = [last_tok, nil]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
unless skip
|
111
|
+
case t.event
|
112
|
+
when :on_kw
|
113
|
+
case t.tok
|
114
|
+
when 'begin', 'class', 'module', 'do', 'case'
|
115
|
+
opens << [t, nil]
|
116
|
+
when 'end'
|
117
|
+
opens.pop
|
118
|
+
when 'def'
|
119
|
+
opens << [t, :in_method_head, [:receiver, :name]]
|
120
|
+
when 'if', 'unless'
|
121
|
+
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
122
|
+
opens << [t, nil]
|
123
|
+
end
|
124
|
+
when 'while', 'until'
|
125
|
+
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
126
|
+
opens << [t, :in_for_while_until_condition]
|
127
|
+
end
|
128
|
+
when 'ensure', 'rescue'
|
129
|
+
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
130
|
+
opens.pop
|
131
|
+
opens << [t, nil]
|
132
|
+
end
|
133
|
+
when 'elsif', 'else', 'when'
|
134
|
+
opens.pop
|
135
|
+
opens << [t, nil]
|
136
|
+
when 'for'
|
137
|
+
opens << [t, :in_for_while_until_condition]
|
138
|
+
when 'in'
|
139
|
+
if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
|
140
|
+
opens.pop
|
141
|
+
opens << [t, nil]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
when :on_tlambda
|
145
|
+
opens << [t, :in_lambda_head]
|
146
|
+
when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
|
147
|
+
opens << [t, nil]
|
148
|
+
when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
|
149
|
+
opens.pop
|
150
|
+
when :on_heredoc_beg
|
151
|
+
pending_heredocs << t
|
152
|
+
when :on_heredoc_end
|
153
|
+
opens.pop
|
154
|
+
when :on_backtick
|
155
|
+
opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
|
156
|
+
when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
|
157
|
+
opens << [t, nil]
|
158
|
+
when :on_tstring_end, :on_regexp_end, :on_label_end
|
159
|
+
opens.pop
|
160
|
+
when :on_symbeg
|
161
|
+
if t.tok == ':'
|
162
|
+
opens << [t, :in_unquoted_symbol]
|
163
|
+
else
|
164
|
+
opens << [t, nil]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
if t.event == :on_nl || t.event == :on_semicolon
|
169
|
+
first_token_on_line = true
|
170
|
+
elsif t.event != :on_sp
|
171
|
+
first_token_on_line = false
|
172
|
+
end
|
173
|
+
if pending_heredocs.any? && t.tok.include?("\n")
|
174
|
+
pending_heredocs.reverse_each { |t| opens << [t, nil] }
|
175
|
+
pending_heredocs = []
|
176
|
+
end
|
177
|
+
yield t, opens if block_given?
|
178
|
+
end
|
179
|
+
opens.map(&:first) + pending_heredocs.reverse
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.open_tokens(tokens)
|
183
|
+
# scan_opens without block will return a list of open tokens at last token position
|
184
|
+
scan_opens(tokens)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
|
188
|
+
# Example code
|
189
|
+
# ["hello
|
190
|
+
# world"+(
|
191
|
+
# First line
|
192
|
+
# line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
|
193
|
+
# prev_opens: []
|
194
|
+
# next_tokens: [lbracket, tstring_beg]
|
195
|
+
# min_depth: 0 (minimum at beginning of line)
|
196
|
+
# Second line
|
197
|
+
# line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
|
198
|
+
# prev_opens: [lbracket, tstring_beg]
|
199
|
+
# next_tokens: [lbracket, lparen]
|
200
|
+
# min_depth: 1 (minimum just after tstring_end)
|
201
|
+
def self.parse_by_line(tokens)
|
202
|
+
line_tokens = []
|
203
|
+
prev_opens = []
|
204
|
+
min_depth = 0
|
205
|
+
output = []
|
206
|
+
last_opens = scan_opens(tokens) do |t, opens|
|
207
|
+
depth = t == opens.last&.first ? opens.size - 1 : opens.size
|
208
|
+
min_depth = depth if depth < min_depth
|
209
|
+
if t.tok.include?("\n")
|
210
|
+
t.tok.each_line do |line|
|
211
|
+
line_tokens << [t, line]
|
212
|
+
next if line[-1] != "\n"
|
213
|
+
next_opens = opens.map(&:first)
|
214
|
+
output << [line_tokens, prev_opens, next_opens, min_depth]
|
215
|
+
prev_opens = next_opens
|
216
|
+
min_depth = prev_opens.size
|
217
|
+
line_tokens = []
|
218
|
+
end
|
219
|
+
else
|
220
|
+
line_tokens << [t, t.tok]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
|
224
|
+
output
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|