brakeman 1.8.3 → 1.9.0.pre1

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 (63) hide show
  1. data/README.md +3 -27
  2. data/lib/brakeman.rb +36 -38
  3. data/lib/brakeman/app_tree.rb +90 -0
  4. data/lib/brakeman/call_index.rb +5 -38
  5. data/lib/brakeman/checks.rb +11 -11
  6. data/lib/brakeman/checks/base_check.rb +53 -29
  7. data/lib/brakeman/checks/check_cross_site_scripting.rb +11 -9
  8. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  9. data/lib/brakeman/checks/check_execute.rb +3 -3
  10. data/lib/brakeman/checks/check_link_to.rb +15 -13
  11. data/lib/brakeman/checks/check_link_to_href.rb +1 -1
  12. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  13. data/lib/brakeman/checks/check_mass_assignment.rb +27 -13
  14. data/lib/brakeman/checks/check_redirect.rb +4 -4
  15. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  16. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  17. data/lib/brakeman/checks/check_send.rb +2 -2
  18. data/lib/brakeman/checks/check_session_settings.rb +12 -5
  19. data/lib/brakeman/checks/check_single_quotes.rb +3 -3
  20. data/lib/brakeman/checks/check_skip_before_filter.rb +4 -3
  21. data/lib/brakeman/checks/check_sql.rb +30 -30
  22. data/lib/brakeman/checks/check_translate_bug.rb +11 -10
  23. data/lib/brakeman/checks/check_validation_regex.rb +36 -11
  24. data/lib/brakeman/checks/check_without_protection.rb +1 -1
  25. data/lib/brakeman/options.rb +6 -2
  26. data/lib/brakeman/processor.rb +6 -5
  27. data/lib/brakeman/processors/alias_processor.rb +153 -38
  28. data/lib/brakeman/processors/base_processor.rb +16 -21
  29. data/lib/brakeman/processors/controller_alias_processor.rb +24 -11
  30. data/lib/brakeman/processors/controller_processor.rb +25 -25
  31. data/lib/brakeman/processors/erb_template_processor.rb +6 -7
  32. data/lib/brakeman/processors/erubis_template_processor.rb +2 -3
  33. data/lib/brakeman/processors/gem_processor.rb +5 -4
  34. data/lib/brakeman/processors/haml_template_processor.rb +4 -6
  35. data/lib/brakeman/processors/lib/find_all_calls.rb +3 -3
  36. data/lib/brakeman/processors/lib/find_call.rb +2 -2
  37. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  38. data/lib/brakeman/processors/lib/processor_helper.rb +24 -2
  39. data/lib/brakeman/processors/lib/rails2_config_processor.rb +13 -14
  40. data/lib/brakeman/processors/lib/rails2_route_processor.rb +9 -4
  41. data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -8
  42. data/lib/brakeman/processors/lib/rails3_route_processor.rb +23 -21
  43. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  44. data/lib/brakeman/processors/library_processor.rb +2 -2
  45. data/lib/brakeman/processors/model_processor.rb +16 -12
  46. data/lib/brakeman/processors/output_processor.rb +2 -1
  47. data/lib/brakeman/processors/template_alias_processor.rb +12 -8
  48. data/lib/brakeman/report.rb +28 -14
  49. data/lib/brakeman/rescanner.rb +5 -5
  50. data/lib/brakeman/scanner.rb +56 -94
  51. data/lib/brakeman/templates/header.html.erb +7 -2
  52. data/lib/brakeman/tracker.rb +14 -4
  53. data/lib/brakeman/util.rb +38 -17
  54. data/lib/brakeman/version.rb +1 -1
  55. data/lib/brakeman/warning.rb +14 -6
  56. data/lib/ruby_parser/bm_sexp.rb +157 -57
  57. data/lib/ruby_parser/bm_sexp_processor.rb +1 -2
  58. metadata +26 -25
  59. data/lib/ruby_parser/ruby18_parser.rb +0 -5544
  60. data/lib/ruby_parser/ruby19_parser.rb +0 -5756
  61. data/lib/ruby_parser/ruby_lexer.rb +0 -1349
  62. data/lib/ruby_parser/ruby_parser.rb +0 -5
  63. data/lib/ruby_parser/ruby_parser_extras.rb +0 -1057
@@ -1,1349 +0,0 @@
1
- class RubyLexer
2
- attr_accessor :command_start
3
- attr_accessor :cmdarg
4
- attr_accessor :cond
5
- attr_accessor :nest
6
-
7
- ESC_RE = /\\([0-7]{1,3}|x[0-9a-fA-F]{1,2}|M-[^\\]|(C-|c)[^\\]|[^0-7xMCc])/
8
-
9
- ##
10
- # What version of ruby to parse. 18 and 19 are the only valid values
11
- # currently supported.
12
-
13
- attr_accessor :version
14
-
15
- # Additional context surrounding tokens that both the lexer and
16
- # grammar use.
17
- attr_reader :lex_state
18
-
19
- attr_accessor :lex_strterm
20
-
21
- attr_accessor :parser # HACK for very end of lexer... *sigh*
22
-
23
- # Stream of data that yylex examines.
24
- attr_reader :src
25
-
26
- # Last token read via yylex.
27
- attr_accessor :token
28
-
29
- attr_accessor :string_buffer
30
-
31
- # Value of last token which had a value associated with it.
32
- attr_accessor :yacc_value
33
-
34
- # What handles warnings
35
- attr_accessor :warnings
36
-
37
- EOF = :eof_haha!
38
-
39
- # ruby constants for strings (should this be moved somewhere else?)
40
- STR_FUNC_BORING = 0x00
41
- STR_FUNC_ESCAPE = 0x01 # TODO: remove and replace with REGEXP
42
- STR_FUNC_EXPAND = 0x02
43
- STR_FUNC_REGEXP = 0x04
44
- STR_FUNC_AWORDS = 0x08
45
- STR_FUNC_SYMBOL = 0x10
46
- STR_FUNC_INDENT = 0x20 # <<-HEREDOC
47
-
48
- STR_SQUOTE = STR_FUNC_BORING
49
- STR_DQUOTE = STR_FUNC_BORING | STR_FUNC_EXPAND
50
- STR_XQUOTE = STR_FUNC_BORING | STR_FUNC_EXPAND
51
- STR_REGEXP = STR_FUNC_REGEXP | STR_FUNC_ESCAPE | STR_FUNC_EXPAND
52
- STR_SSYM = STR_FUNC_SYMBOL
53
- STR_DSYM = STR_FUNC_SYMBOL | STR_FUNC_EXPAND
54
-
55
- TOKENS = {
56
- "!" => :tBANG,
57
- "!=" => :tNEQ,
58
- "!~" => :tNMATCH,
59
- "," => :tCOMMA,
60
- ".." => :tDOT2,
61
- "..." => :tDOT3,
62
- "=" => :tEQL,
63
- "==" => :tEQ,
64
- "===" => :tEQQ,
65
- "=>" => :tASSOC,
66
- "=~" => :tMATCH,
67
- "->" => :tLAMBDA,
68
- }
69
-
70
- # How the parser advances to the next token.
71
- #
72
- # @return true if not at end of file (EOF).
73
-
74
- def advance
75
- r = yylex
76
- self.token = r
77
-
78
- raise "yylex returned nil" unless r
79
-
80
- return RubyLexer::EOF != r
81
- end
82
-
83
- def arg_ambiguous
84
- self.warning("Ambiguous first argument. make sure.")
85
- end
86
-
87
- def comments
88
- c = @comments.join
89
- @comments.clear
90
- c
91
- end
92
-
93
- def expr_beg_push val
94
- cond.push false
95
- cmdarg.push false
96
- self.lex_state = :expr_beg
97
- self.yacc_value = val
98
- end
99
-
100
- def fix_arg_lex_state
101
- self.lex_state = if lex_state == :expr_fname || lex_state == :expr_dot
102
- :expr_arg
103
- else
104
- :expr_beg
105
- end
106
- end
107
-
108
- def heredoc here # 63 lines
109
- _, eos, func, last_line = here
110
-
111
- indent = (func & STR_FUNC_INDENT) != 0
112
- expand = (func & STR_FUNC_EXPAND) != 0
113
- eos_re = indent ? /[ \t]*#{eos}(\r?\n|\z)/ : /#{eos}(\r?\n|\z)/
114
- err_msg = "can't match #{eos_re.inspect} anywhere in "
115
-
116
- rb_compile_error err_msg if
117
- src.eos?
118
-
119
- if src.beginning_of_line? && src.scan(eos_re) then
120
- src.unread_many last_line # TODO: figure out how to remove this
121
- self.yacc_value = eos
122
- return :tSTRING_END
123
- end
124
-
125
- self.string_buffer = []
126
-
127
- if expand then
128
- case
129
- when src.scan(/#[$@]/) then
130
- src.pos -= 1 # FIX omg stupid
131
- self.yacc_value = src.matched
132
- return :tSTRING_DVAR
133
- when src.scan(/#[{]/) then
134
- self.yacc_value = src.matched
135
- return :tSTRING_DBEG
136
- when src.scan(/#/) then
137
- string_buffer << '#'
138
- end
139
-
140
- until src.check(eos_re) do
141
- c = tokadd_string func, "\n", nil
142
-
143
- rb_compile_error err_msg if
144
- c == RubyLexer::EOF
145
-
146
- if c != "\n" then
147
- self.yacc_value = string_buffer.join.delete("\r")
148
- return :tSTRING_CONTENT
149
- else
150
- string_buffer << src.scan(/\n/)
151
- end
152
-
153
- rb_compile_error err_msg if
154
- src.eos?
155
- end
156
- else
157
- until src.check(eos_re) do
158
- string_buffer << src.scan(/.*(\n|\z)/)
159
- rb_compile_error err_msg if
160
- src.eos?
161
- end
162
- end
163
-
164
- self.lex_strterm = [:heredoc, eos, func, last_line]
165
- self.yacc_value = string_buffer.join.delete("\r")
166
-
167
- return :tSTRING_CONTENT
168
- end
169
-
170
- def heredoc_identifier # 51 lines
171
- term, func = nil, STR_FUNC_BORING
172
- self.string_buffer = []
173
-
174
- case
175
- when src.scan(/(-?)(['"`])(.*?)\2/) then
176
- term = src[2]
177
- unless src[1].empty? then
178
- func |= STR_FUNC_INDENT
179
- end
180
- func |= case term
181
- when "\'" then
182
- STR_SQUOTE
183
- when '"' then
184
- STR_DQUOTE
185
- else
186
- STR_XQUOTE
187
- end
188
- string_buffer << src[3]
189
- when src.scan(/-?(['"`])(?!\1*\Z)/) then
190
- rb_compile_error "unterminated here document identifier"
191
- when src.scan(/(-?)(\w+)/) then
192
- term = '"'
193
- func |= STR_DQUOTE
194
- unless src[1].empty? then
195
- func |= STR_FUNC_INDENT
196
- end
197
- string_buffer << src[2]
198
- else
199
- return nil
200
- end
201
-
202
- if src.scan(/.*\n/) then
203
- # TODO: think about storing off the char range instead
204
- line = src.matched
205
- src.extra_lines_added += 1
206
- else
207
- line = nil
208
- end
209
-
210
- self.lex_strterm = [:heredoc, string_buffer.join, func, line]
211
-
212
- if term == '`' then
213
- self.yacc_value = "`"
214
- return :tXSTRING_BEG
215
- else
216
- self.yacc_value = "\""
217
- return :tSTRING_BEG
218
- end
219
- end
220
-
221
- def initialize v = 18
222
- self.version = v
223
- self.cond = RubyParser::StackState.new(:cond)
224
- self.cmdarg = RubyParser::StackState.new(:cmdarg)
225
- self.nest = 0
226
- @comments = []
227
-
228
- reset
229
- end
230
-
231
- def int_with_base base
232
- rb_compile_error "Invalid numeric format" if src.matched =~ /__/
233
- self.yacc_value = src.matched.to_i(base)
234
- return :tINTEGER
235
- end
236
-
237
- def lex_state= o
238
- raise "wtf\?" unless Symbol === o
239
- @lex_state = o
240
- end
241
-
242
- attr_writer :lineno
243
- def lineno
244
- @lineno ||= src.lineno
245
- end
246
-
247
- ##
248
- # Parse a number from the input stream.
249
- #
250
- # @param c The first character of the number.
251
- # @return A int constant wich represents a token.
252
-
253
- def parse_number
254
- self.lex_state = :expr_end
255
-
256
- case
257
- when src.scan(/[+-]?0[xbd]\b/) then
258
- rb_compile_error "Invalid numeric format"
259
- when src.scan(/[+-]?0x[a-f0-9_]+/i) then
260
- int_with_base(16)
261
- when src.scan(/[+-]?0b[01_]+/) then
262
- int_with_base(2)
263
- when src.scan(/[+-]?0d[0-9_]+/) then
264
- int_with_base(10)
265
- when src.scan(/[+-]?0[Oo]?[0-7_]*[89]/) then
266
- rb_compile_error "Illegal octal digit."
267
- when src.scan(/[+-]?0[Oo]?[0-7_]+|0[Oo]/) then
268
- int_with_base(8)
269
- when src.scan(/[+-]?[\d_]+_(e|\.)/) then
270
- rb_compile_error "Trailing '_' in number."
271
- when src.scan(/[+-]?[\d_]+\.[\d_]+(e[+-]?[\d_]+)?\b|[+-]?[\d_]+e[+-]?[\d_]+\b/i) then
272
- number = src.matched
273
- if number =~ /__/ then
274
- rb_compile_error "Invalid numeric format"
275
- end
276
- self.yacc_value = number.to_f
277
- :tFLOAT
278
- when src.scan(/[+-]?0\b/) then
279
- int_with_base(10)
280
- when src.scan(/[+-]?[\d_]+\b/) then
281
- int_with_base(10)
282
- else
283
- rb_compile_error "Bad number format"
284
- end
285
- end
286
-
287
- def parse_quote # 58 lines
288
- beg, nnd, short_hand, c = nil, nil, false, nil
289
-
290
- if src.scan(/[a-z0-9]{1,2}/i) then # Long-hand (e.g. %Q{}).
291
- rb_compile_error "unknown type of %string" if src.matched_size == 2
292
- c, beg, short_hand = src.matched, src.getch, false
293
- else # Short-hand (e.g. %{, %., %!, etc)
294
- c, beg, short_hand = 'Q', src.getch, true
295
- end
296
-
297
- if src.eos? or c == RubyLexer::EOF or beg == RubyLexer::EOF then
298
- rb_compile_error "unterminated quoted string meets end of file"
299
- end
300
-
301
- # Figure nnd-char. "\0" is special to indicate beg=nnd and that no nesting?
302
- nnd = { "(" => ")", "[" => "]", "{" => "}", "<" => ">" }[beg]
303
- nnd, beg = beg, "\0" if nnd.nil?
304
-
305
- token_type, self.yacc_value = nil, "%#{c}#{beg}"
306
- token_type, string_type = case c
307
- when 'Q' then
308
- ch = short_hand ? nnd : c + beg
309
- self.yacc_value = "%#{ch}"
310
- [:tSTRING_BEG, STR_DQUOTE]
311
- when 'q' then
312
- [:tSTRING_BEG, STR_SQUOTE]
313
- when 'W' then
314
- src.scan(/\s*/)
315
- [:tWORDS_BEG, STR_DQUOTE | STR_FUNC_AWORDS]
316
- when 'w' then
317
- src.scan(/\s*/)
318
- [:tAWORDS_BEG, STR_SQUOTE | STR_FUNC_AWORDS]
319
- when 'x' then
320
- [:tXSTRING_BEG, STR_XQUOTE]
321
- when 'r' then
322
- [:tREGEXP_BEG, STR_REGEXP]
323
- when 's' then
324
- self.lex_state = :expr_fname
325
- [:tSYMBEG, STR_SSYM]
326
- end
327
-
328
- rb_compile_error "Bad %string type. Expected [Qqwxr\W], found '#{c}'." if
329
- token_type.nil?
330
-
331
- self.lex_strterm = [:strterm, string_type, nnd, beg]
332
-
333
- return token_type
334
- end
335
-
336
- def parse_string(quote) # 65 lines
337
- _, string_type, term, open = quote
338
-
339
- space = false # FIX: remove these
340
- func = string_type
341
- paren = open
342
- term_re = Regexp.escape term
343
-
344
- awords = (func & STR_FUNC_AWORDS) != 0
345
- regexp = (func & STR_FUNC_REGEXP) != 0
346
- expand = (func & STR_FUNC_EXPAND) != 0
347
-
348
- unless func then # FIX: impossible, prolly needs == 0
349
- self.lineno = nil
350
- return :tSTRING_END
351
- end
352
-
353
- space = true if awords and src.scan(/\s+/)
354
-
355
- if self.nest == 0 && src.scan(/#{term_re}/) then
356
- if awords then
357
- quote[1] = nil
358
- return :tSPACE
359
- elsif regexp then
360
- self.yacc_value = self.regx_options
361
- self.lineno = nil
362
- return :tREGEXP_END
363
- else
364
- self.yacc_value = term
365
- self.lineno = nil
366
- return :tSTRING_END
367
- end
368
- end
369
-
370
- if space then
371
- return :tSPACE
372
- end
373
-
374
- self.string_buffer = []
375
-
376
- if expand
377
- case
378
- when src.scan(/#(?=[$@])/) then
379
- return :tSTRING_DVAR
380
- when src.scan(/#[{]/) then
381
- return :tSTRING_DBEG
382
- when src.scan(/#/) then
383
- string_buffer << '#'
384
- end
385
- end
386
-
387
- if tokadd_string(func, term, paren) == RubyLexer::EOF then
388
- rb_compile_error "unterminated string meets end of file"
389
- end
390
-
391
- self.yacc_value = string_buffer.join
392
-
393
- return :tSTRING_CONTENT
394
- end
395
-
396
- def rb_compile_error msg
397
- msg += ". near line #{self.lineno}: #{src.rest[/^.*/].inspect}"
398
- raise SyntaxError, msg
399
- end
400
-
401
- def read_escape # 51 lines
402
- case
403
- when src.scan(/\\/) then # Backslash
404
- '\\'
405
- when src.scan(/n/) then # newline
406
- "\n"
407
- when src.scan(/t/) then # horizontal tab
408
- "\t"
409
- when src.scan(/r/) then # carriage-return
410
- "\r"
411
- when src.scan(/f/) then # form-feed
412
- "\f"
413
- when src.scan(/v/) then # vertical tab
414
- "\13"
415
- when src.scan(/a/) then # alarm(bell)
416
- "\007"
417
- when src.scan(/e/) then # escape
418
- "\033"
419
- when src.scan(/b/) then # backspace
420
- "\010"
421
- when src.scan(/s/) then # space
422
- " "
423
- when src.scan(/[0-7]{1,3}/) then # octal constant
424
- src.matched.to_i(8).chr
425
- when src.scan(/x([0-9a-fA-F]{1,2})/) then # hex constant
426
- src[1].to_i(16).chr
427
- when src.check(/M-\\[\\MCc]/) then
428
- src.scan(/M-\\/) # eat it
429
- c = self.read_escape
430
- c[0] = (c[0].ord | 0x80).chr
431
- c
432
- when src.scan(/M-(.)/) then
433
- c = src[1]
434
- c[0] = (c[0].ord | 0x80).chr
435
- c
436
- when src.check(/(C-|c)\\[\\MCc]/) then
437
- src.scan(/(C-|c)\\/) # eat it
438
- c = self.read_escape
439
- c[0] = (c[0].ord & 0x9f).chr
440
- c
441
- when src.scan(/C-\?|c\?/) then
442
- 127.chr
443
- when src.scan(/(C-|c)(.)/) then
444
- c = src[2]
445
- c[0] = (c[0].ord & 0x9f).chr
446
- c
447
- when src.scan(/[McCx0-9]/) || src.eos? then
448
- rb_compile_error("Invalid escape character syntax")
449
- else
450
- src.getch
451
- end
452
- end
453
-
454
- def regx_options # 15 lines
455
- good, bad = [], []
456
-
457
- if src.scan(/[a-z]+/) then
458
- good, bad = src.matched.split(//).partition { |s| s =~ /^[ixmonesu]$/ }
459
- end
460
-
461
- unless bad.empty? then
462
- rb_compile_error("unknown regexp option%s - %s" %
463
- [(bad.size > 1 ? "s" : ""), bad.join.inspect])
464
- end
465
-
466
- return good.join
467
- end
468
-
469
- def reset
470
- self.command_start = true
471
- self.lex_strterm = nil
472
- self.token = nil
473
- self.yacc_value = nil
474
-
475
- @src = nil
476
- @lex_state = nil
477
- end
478
-
479
- def src= src
480
- raise "bad src: #{src.inspect}" unless String === src
481
- @src = RPStringScanner.new(src)
482
- end
483
-
484
- def tokadd_escape term # 20 lines
485
- case
486
- when src.scan(/\\\n/) then
487
- # just ignore
488
- when src.scan(/\\([0-7]{1,3}|x[0-9a-fA-F]{1,2})/) then
489
- self.string_buffer << src.matched
490
- when src.scan(/\\([MC]-|c)(?=\\)/) then
491
- self.string_buffer << src.matched
492
- self.tokadd_escape term
493
- when src.scan(/\\([MC]-|c)(.)/) then
494
- self.string_buffer << src.matched
495
- when src.scan(/\\[McCx]/) then
496
- rb_compile_error "Invalid escape character syntax"
497
- when src.scan(/\\(.)/m) then
498
- self.string_buffer << src.matched
499
- else
500
- rb_compile_error "Invalid escape character syntax"
501
- end
502
- end
503
-
504
- def tokadd_string(func, term, paren) # 105 lines
505
- awords = (func & STR_FUNC_AWORDS) != 0
506
- escape = (func & STR_FUNC_ESCAPE) != 0
507
- expand = (func & STR_FUNC_EXPAND) != 0
508
- regexp = (func & STR_FUNC_REGEXP) != 0
509
- symbol = (func & STR_FUNC_SYMBOL) != 0
510
-
511
- paren_re = paren.nil? ? nil : Regexp.new(Regexp.escape(paren))
512
- term_re = Regexp.new(Regexp.escape(term))
513
-
514
- until src.eos? do
515
- c = nil
516
- handled = true
517
- case
518
- when self.nest == 0 && src.scan(term_re) then
519
- src.pos -= 1
520
- break
521
- when paren_re && src.scan(paren_re) then
522
- self.nest += 1
523
- when src.scan(term_re) then
524
- self.nest -= 1
525
- when awords && src.scan(/\s/) then
526
- src.pos -= 1
527
- break
528
- when expand && src.scan(/#(?=[\$\@\{])/) then
529
- src.pos -= 1
530
- break
531
- when expand && src.scan(/#(?!\n)/) then
532
- # do nothing
533
- when src.check(/\\/) then
534
- case
535
- when awords && src.scan(/\\\n/) then
536
- string_buffer << "\n"
537
- next
538
- when awords && src.scan(/\\\s/) then
539
- c = ' '
540
- when expand && src.scan(/\\\n/) then
541
- next
542
- when regexp && src.check(/\\/) then
543
- self.tokadd_escape term
544
- next
545
- when expand && src.scan(/\\/) then
546
- c = self.read_escape
547
- when src.scan(/\\\n/) then
548
- # do nothing
549
- when src.scan(/\\\\/) then
550
- string_buffer << '\\' if escape
551
- c = '\\'
552
- when src.scan(/\\/) then
553
- unless src.scan(term_re) || paren.nil? || src.scan(paren_re) then
554
- string_buffer << "\\"
555
- end
556
- else
557
- handled = false
558
- end
559
- else
560
- handled = false
561
- end # case
562
-
563
- unless handled then
564
-
565
- t = Regexp.escape term
566
- x = Regexp.escape(paren) if paren && paren != "\000"
567
- re = if awords then
568
- /[^#{t}#{x}\#\0\\\n\ ]+|./ # |. to pick up whatever
569
- else
570
- /[^#{t}#{x}\#\0\\]+|./
571
- end
572
-
573
- src.scan re
574
- c = src.matched
575
-
576
- rb_compile_error "symbol cannot contain '\\0'" if symbol && c =~ /\0/
577
- end # unless handled
578
-
579
- c ||= src.matched
580
- string_buffer << c
581
- end # until
582
-
583
- c ||= src.matched
584
- c = RubyLexer::EOF if src.eos?
585
-
586
-
587
- return c
588
- end
589
-
590
- def unescape s
591
-
592
- r = {
593
- "a" => "\007",
594
- "b" => "\010",
595
- "e" => "\033",
596
- "f" => "\f",
597
- "n" => "\n",
598
- "r" => "\r",
599
- "s" => " ",
600
- "t" => "\t",
601
- "v" => "\13",
602
- "\\" => '\\',
603
- "\n" => "",
604
- "C-\?" => 127.chr,
605
- "c\?" => 127.chr,
606
- }[s]
607
-
608
- return r if r
609
-
610
- case s
611
- when /^[0-7]{1,3}/ then
612
- $&.to_i(8).chr
613
- when /^x([0-9a-fA-F]{1,2})/ then
614
- $1.to_i(16).chr
615
- when /^M-(.)/ then
616
- ($1[0].ord | 0x80).chr
617
- when /^(C-|c)(.)/ then
618
- ($2[0].ord & 0x9f).chr
619
- when /^[McCx0-9]/ then
620
- rb_compile_error("Invalid escape character syntax")
621
- else
622
- s
623
- end
624
- end
625
-
626
- def warning s
627
- # do nothing for now
628
- end
629
-
630
- ##
631
- # Returns the next token. Also sets yy_val is needed.
632
- #
633
- # @return Description of the Returned Value
634
-
635
- def yylex # 826 lines
636
-
637
- c = ''
638
- space_seen = false
639
- command_state = false
640
- src = self.src
641
-
642
- self.token = nil
643
- self.yacc_value = nil
644
-
645
- return yylex_string if lex_strterm
646
-
647
- command_state = self.command_start
648
- self.command_start = false
649
-
650
- last_state = lex_state
651
-
652
- loop do # START OF CASE
653
- if src.scan(/[\ \t\r\f\v]/) then # \s - \n + \v
654
- space_seen = true
655
- next
656
- elsif src.check(/[^a-zA-Z]/) then
657
- if src.scan(/\n|#/) then
658
- self.lineno = nil
659
- c = src.matched
660
- if c == '#' then
661
- src.pos -= 1
662
-
663
- while src.scan(/\s*#.*(\n+|\z)/) do
664
- @comments << src.matched.gsub(/^ +#/, '#').gsub(/^ +$/, '')
665
- end
666
-
667
- if src.eos? then
668
- return RubyLexer::EOF
669
- end
670
- end
671
-
672
- # Replace a string of newlines with a single one
673
- src.scan(/\n+/)
674
-
675
- if [:expr_beg, :expr_fname,
676
- :expr_dot, :expr_class].include? lex_state then
677
- next
678
- end
679
-
680
- self.command_start = true
681
- self.lex_state = :expr_beg
682
- return :tNL
683
- elsif src.scan(/[\]\)\}]/) then
684
- cond.lexpop
685
- cmdarg.lexpop
686
- self.lex_state = :expr_end
687
- self.yacc_value = src.matched
688
- result = {
689
- ")" => :tRPAREN,
690
- "]" => :tRBRACK,
691
- "}" => :tRCURLY
692
- }[src.matched]
693
- return result
694
- elsif src.scan(/\.\.\.?|,|![=~]?/) then
695
- self.lex_state = :expr_beg
696
- tok = self.yacc_value = src.matched
697
- return TOKENS[tok]
698
- elsif src.check(/\./) then
699
- if src.scan(/\.\d/) then
700
- rb_compile_error "no .<digit> floating literal anymore put 0 before dot"
701
- elsif src.scan(/\./) then
702
- self.lex_state = :expr_dot
703
- self.yacc_value = "."
704
- return :tDOT
705
- end
706
- elsif src.scan(/\(/) then
707
- result = :tLPAREN2
708
-
709
- if lex_state == :expr_beg || lex_state == :expr_mid then
710
- result = :tLPAREN
711
- elsif space_seen then
712
- if lex_state == :expr_cmdarg then
713
- result = :tLPAREN_ARG
714
- elsif lex_state == :expr_arg then
715
- warning("don't put space before argument parentheses")
716
- result = :tLPAREN2
717
- end
718
- end
719
-
720
- self.expr_beg_push "("
721
-
722
- return result
723
- elsif src.check(/\=/) then
724
- if src.scan(/\=\=\=|\=\=|\=~|\=>|\=(?!begin\b)/) then
725
- self.fix_arg_lex_state
726
- tok = self.yacc_value = src.matched
727
- return TOKENS[tok]
728
- elsif src.scan(/\=begin(?=\s)/) then
729
- # @comments << '=' << src.matched
730
- @comments << src.matched
731
-
732
- unless src.scan(/.*?\n=end( |\t|\f)*[^\n]*(\n|\z)/m) then
733
- @comments.clear
734
- rb_compile_error("embedded document meets end of file")
735
- end
736
-
737
- @comments << src.matched
738
-
739
- next
740
- else
741
- raise "you shouldn't be able to get here"
742
- end
743
- elsif src.scan(/\"(#{ESC_RE}|#(#{ESC_RE}|[^\{\#\@\$\"\\])|[^\"\\\#])*\"/o) then
744
- self.yacc_value = src.matched[1..-2].gsub(ESC_RE) { unescape $1 }
745
- self.lex_state = :expr_end
746
- return :tSTRING
747
- elsif src.scan(/\"/) then # FALLBACK
748
- self.lex_strterm = [:strterm, STR_DQUOTE, '"', "\0"] # TODO: question this
749
- self.yacc_value = "\""
750
- return :tSTRING_BEG
751
- elsif src.scan(/\@\@?\w*/) then
752
- self.token = src.matched
753
-
754
- rb_compile_error "`#{token}` is not allowed as a variable name" if
755
- token =~ /\@\d/
756
-
757
- return process_token(command_state)
758
- elsif src.scan(/\:\:/) then
759
- if (lex_state == :expr_beg ||
760
- lex_state == :expr_mid ||
761
- lex_state == :expr_class ||
762
- (lex_state.is_argument && space_seen)) then
763
- self.lex_state = :expr_beg
764
- self.yacc_value = "::"
765
- return :tCOLON3
766
- end
767
-
768
- self.lex_state = :expr_dot
769
- self.yacc_value = "::"
770
- return :tCOLON2
771
- elsif lex_state != :expr_end && lex_state != :expr_endarg && src.scan(/:([a-zA-Z_]\w*(?:[?!]|=(?!>))?)/) then
772
- self.yacc_value = src[1]
773
- self.lex_state = :expr_end
774
- return :tSYMBOL
775
- elsif src.scan(/\:/) then
776
- # ?: / then / when
777
- if (lex_state == :expr_end || lex_state == :expr_endarg||
778
- src.check(/\s/)) then
779
- self.lex_state = :expr_beg
780
- self.yacc_value = ":"
781
- return :tCOLON
782
- end
783
-
784
- case
785
- when src.scan(/\'/) then
786
- self.lex_strterm = [:strterm, STR_SSYM, src.matched, "\0"]
787
- when src.scan(/\"/) then
788
- self.lex_strterm = [:strterm, STR_DSYM, src.matched, "\0"]
789
- end
790
-
791
- self.lex_state = :expr_fname
792
- self.yacc_value = ":"
793
- return :tSYMBEG
794
- elsif src.check(/[0-9]/) then
795
- return parse_number
796
- elsif src.scan(/\[/) then
797
- result = src.matched
798
-
799
- if lex_state == :expr_fname || lex_state == :expr_dot then
800
- self.lex_state = :expr_arg
801
- case
802
- when src.scan(/\]\=/) then
803
- self.yacc_value = "[]="
804
- return :tASET
805
- when src.scan(/\]/) then
806
- self.yacc_value = "[]"
807
- return :tAREF
808
- else
809
- rb_compile_error "unexpected '['"
810
- end
811
- elsif lex_state == :expr_beg || lex_state == :expr_mid then
812
- result = :tLBRACK
813
- elsif lex_state.is_argument && space_seen then
814
- result = :tLBRACK
815
- end
816
-
817
- self.expr_beg_push "["
818
-
819
- return result
820
- elsif src.scan(/\'(\\.|[^\'])*\'/) then
821
- self.yacc_value = src.matched[1..-2].gsub(/\\\\/, "\\").gsub(/\\'/, "'")
822
- self.lex_state = :expr_end
823
- return :tSTRING
824
- elsif src.check(/\|/) then
825
- if src.scan(/\|\|\=/) then
826
- self.lex_state = :expr_beg
827
- self.yacc_value = "||"
828
- return :tOP_ASGN
829
- elsif src.scan(/\|\|/) then
830
- self.lex_state = :expr_beg
831
- self.yacc_value = "||"
832
- return :tOROP
833
- elsif src.scan(/\|\=/) then
834
- self.lex_state = :expr_beg
835
- self.yacc_value = "|"
836
- return :tOP_ASGN
837
- elsif src.scan(/\|/) then
838
- self.fix_arg_lex_state
839
- self.yacc_value = "|"
840
- return :tPIPE
841
- end
842
- elsif src.scan(/\{/) then
843
- if defined?(@hack_expects_lambda) && @hack_expects_lambda
844
- @hack_expects_lambda = false
845
- self.lex_state = :expr_beg
846
- return :tLAMBEG
847
- end
848
-
849
- result = if lex_state.is_argument || lex_state == :expr_end then
850
- :tLCURLY # block (primary)
851
- elsif lex_state == :expr_endarg then
852
- :tLBRACE_ARG # block (expr)
853
- else
854
- :tLBRACE # hash
855
- end
856
-
857
- self.expr_beg_push "{"
858
- self.command_start = true unless result == :tLBRACE
859
-
860
- return result
861
- elsif src.scan(/->/) then
862
- @hack_expects_lambda = true
863
- self.lex_state = :expr_arg
864
- return :tLAMBDA
865
- elsif src.scan(/[+-]/) then
866
- sign = src.matched
867
- utype, type = if sign == "+" then
868
- [:tUPLUS, :tPLUS]
869
- else
870
- [:tUMINUS, :tMINUS]
871
- end
872
-
873
- if lex_state == :expr_fname || lex_state == :expr_dot then
874
- self.lex_state = :expr_arg
875
- if src.scan(/@/) then
876
- self.yacc_value = "#{sign}@"
877
- return utype
878
- else
879
- self.yacc_value = sign
880
- return type
881
- end
882
- end
883
-
884
- if src.scan(/\=/) then
885
- self.lex_state = :expr_beg
886
- self.yacc_value = sign
887
- return :tOP_ASGN
888
- end
889
-
890
- if (lex_state == :expr_beg || lex_state == :expr_mid ||
891
- (lex_state.is_argument && space_seen && !src.check(/\s/))) then
892
- if lex_state.is_argument then
893
- arg_ambiguous
894
- end
895
-
896
- self.lex_state = :expr_beg
897
- self.yacc_value = sign
898
-
899
- if src.check(/\d/) then
900
- if utype == :tUPLUS then
901
- return self.parse_number
902
- else
903
- return :tUMINUS_NUM
904
- end
905
- end
906
-
907
- return utype
908
- end
909
-
910
- self.lex_state = :expr_beg
911
- self.yacc_value = sign
912
- return type
913
- elsif src.check(/\*/) then
914
- if src.scan(/\*\*=/) then
915
- self.lex_state = :expr_beg
916
- self.yacc_value = "**"
917
- return :tOP_ASGN
918
- elsif src.scan(/\*\*/) then
919
- self.yacc_value = "**"
920
- self.fix_arg_lex_state
921
- return :tPOW
922
- elsif src.scan(/\*\=/) then
923
- self.lex_state = :expr_beg
924
- self.yacc_value = "*"
925
- return :tOP_ASGN
926
- elsif src.scan(/\*/) then
927
- result = if lex_state.is_argument && space_seen && src.check(/\S/) then
928
- warning("`*' interpreted as argument prefix")
929
- :tSTAR
930
- elsif lex_state == :expr_beg || lex_state == :expr_mid then
931
- :tSTAR
932
- else
933
- :tSTAR2
934
- end
935
- self.yacc_value = "*"
936
- self.fix_arg_lex_state
937
-
938
- return result
939
- end
940
- elsif src.check(/\</) then
941
- if src.scan(/\<\=\>/) then
942
- self.fix_arg_lex_state
943
- self.yacc_value = "<=>"
944
- return :tCMP
945
- elsif src.scan(/\<\=/) then
946
- self.fix_arg_lex_state
947
- self.yacc_value = "<="
948
- return :tLEQ
949
- elsif src.scan(/\<\<\=/) then
950
- self.fix_arg_lex_state
951
- self.lex_state = :expr_beg
952
- self.yacc_value = "\<\<"
953
- return :tOP_ASGN
954
- elsif src.scan(/\<\</) then
955
- if (! [:expr_end, :expr_dot,
956
- :expr_endarg, :expr_class].include?(lex_state) &&
957
- (!lex_state.is_argument || space_seen)) then
958
- tok = self.heredoc_identifier
959
- if tok then
960
- return tok
961
- end
962
- end
963
-
964
- self.fix_arg_lex_state
965
- self.yacc_value = "\<\<"
966
- return :tLSHFT
967
- elsif src.scan(/\</) then
968
- self.fix_arg_lex_state
969
- self.yacc_value = "<"
970
- return :tLT
971
- end
972
- elsif src.check(/\>/) then
973
- if src.scan(/\>\=/) then
974
- self.fix_arg_lex_state
975
- self.yacc_value = ">="
976
- return :tGEQ
977
- elsif src.scan(/\>\>=/) then
978
- self.fix_arg_lex_state
979
- self.lex_state = :expr_beg
980
- self.yacc_value = ">>"
981
- return :tOP_ASGN
982
- elsif src.scan(/\>\>/) then
983
- self.fix_arg_lex_state
984
- self.yacc_value = ">>"
985
- return :tRSHFT
986
- elsif src.scan(/\>/) then
987
- self.fix_arg_lex_state
988
- self.yacc_value = ">"
989
- return :tGT
990
- end
991
- elsif src.scan(/\`/) then
992
- self.yacc_value = "`"
993
- case lex_state
994
- when :expr_fname then
995
- self.lex_state = :expr_end
996
- return :tBACK_REF2
997
- when :expr_dot then
998
- self.lex_state = if command_state then
999
- :expr_cmdarg
1000
- else
1001
- :expr_arg
1002
- end
1003
- return :tBACK_REF2
1004
- end
1005
- self.lex_strterm = [:strterm, STR_XQUOTE, '`', "\0"]
1006
- return :tXSTRING_BEG
1007
- elsif src.scan(/\?/) then
1008
- if lex_state == :expr_end || lex_state == :expr_endarg then
1009
- self.lex_state = :expr_beg
1010
- self.yacc_value = "?"
1011
- return :tEH
1012
- end
1013
-
1014
- if src.eos? then
1015
- rb_compile_error "incomplete character syntax"
1016
- end
1017
-
1018
- if src.check(/\s|\v/) then
1019
- unless lex_state.is_argument then
1020
- c2 = { " " => 's',
1021
- "\n" => 'n',
1022
- "\t" => 't',
1023
- "\v" => 'v',
1024
- "\r" => 'r',
1025
- "\f" => 'f' }[src.matched]
1026
-
1027
- if c2 then
1028
- warning("invalid character syntax; use ?\\" + c2)
1029
- end
1030
- end
1031
-
1032
- # ternary
1033
- self.lex_state = :expr_beg
1034
- self.yacc_value = "?"
1035
- return :tEH
1036
- elsif src.check(/\w(?=\w)/) then # ternary, also
1037
- self.lex_state = :expr_beg
1038
- self.yacc_value = "?"
1039
- return :tEH
1040
- end
1041
-
1042
- c = if src.scan(/\\/) then
1043
- self.read_escape
1044
- else
1045
- src.getch
1046
- end
1047
- self.lex_state = :expr_end
1048
-
1049
- if version == 18 then
1050
- self.yacc_value = c[0].ord & 0xff
1051
- return :tINTEGER
1052
- else
1053
- self.yacc_value = c
1054
- return :tSTRING
1055
- end
1056
- elsif src.check(/\&/) then
1057
- if src.scan(/\&\&\=/) then
1058
- self.yacc_value = "&&"
1059
- self.lex_state = :expr_beg
1060
- return :tOP_ASGN
1061
- elsif src.scan(/\&\&/) then
1062
- self.lex_state = :expr_beg
1063
- self.yacc_value = "&&"
1064
- return :tANDOP
1065
- elsif src.scan(/\&\=/) then
1066
- self.yacc_value = "&"
1067
- self.lex_state = :expr_beg
1068
- return :tOP_ASGN
1069
- elsif src.scan(/&/) then
1070
- result = if lex_state.is_argument && space_seen &&
1071
- !src.check(/\s/) then
1072
- warning("`&' interpreted as argument prefix")
1073
- :tAMPER
1074
- elsif lex_state == :expr_beg || lex_state == :expr_mid then
1075
- :tAMPER
1076
- else
1077
- :tAMPER2
1078
- end
1079
-
1080
- self.fix_arg_lex_state
1081
- self.yacc_value = "&"
1082
- return result
1083
- end
1084
- elsif src.scan(/\//) then
1085
- if lex_state == :expr_beg || lex_state == :expr_mid then
1086
- self.lex_strterm = [:strterm, STR_REGEXP, '/', "\0"]
1087
- self.yacc_value = "/"
1088
- return :tREGEXP_BEG
1089
- end
1090
-
1091
- if src.scan(/\=/) then
1092
- self.yacc_value = "/"
1093
- self.lex_state = :expr_beg
1094
- return :tOP_ASGN
1095
- end
1096
-
1097
- if lex_state.is_argument && space_seen then
1098
- unless src.scan(/\s/) then
1099
- arg_ambiguous
1100
- self.lex_strterm = [:strterm, STR_REGEXP, '/', "\0"]
1101
- self.yacc_value = "/"
1102
- return :tREGEXP_BEG
1103
- end
1104
- end
1105
-
1106
- self.fix_arg_lex_state
1107
- self.yacc_value = "/"
1108
-
1109
- return :tDIVIDE
1110
- elsif src.scan(/\^=/) then
1111
- self.lex_state = :expr_beg
1112
- self.yacc_value = "^"
1113
- return :tOP_ASGN
1114
- elsif src.scan(/\^/) then
1115
- self.fix_arg_lex_state
1116
- self.yacc_value = "^"
1117
- return :tCARET
1118
- elsif src.scan(/\;/) then
1119
- self.command_start = true
1120
- self.lex_state = :expr_beg
1121
- self.yacc_value = ";"
1122
- return :tSEMI
1123
- elsif src.scan(/\~/) then
1124
- if lex_state == :expr_fname || lex_state == :expr_dot then
1125
- src.scan(/@/)
1126
- end
1127
-
1128
- self.fix_arg_lex_state
1129
- self.yacc_value = "~"
1130
-
1131
- return :tTILDE
1132
- elsif src.scan(/\\/) then
1133
- if src.scan(/\n/) then
1134
- self.lineno = nil
1135
- space_seen = true
1136
- next
1137
- end
1138
- rb_compile_error "bare backslash only allowed before newline"
1139
- elsif src.scan(/\%/) then
1140
- if lex_state == :expr_beg || lex_state == :expr_mid then
1141
- return parse_quote
1142
- end
1143
-
1144
- if src.scan(/\=/) then
1145
- self.lex_state = :expr_beg
1146
- self.yacc_value = "%"
1147
- return :tOP_ASGN
1148
- end
1149
-
1150
- if lex_state.is_argument && space_seen && ! src.check(/\s/) then
1151
- return parse_quote
1152
- end
1153
-
1154
- self.fix_arg_lex_state
1155
- self.yacc_value = "%"
1156
-
1157
- return :tPERCENT
1158
- elsif src.check(/\$/) then
1159
- if src.scan(/(\$_)(\w+)/) then
1160
- self.lex_state = :expr_end
1161
- self.token = src.matched
1162
- return process_token(command_state)
1163
- elsif src.scan(/\$_/) then
1164
- self.lex_state = :expr_end
1165
- self.token = src.matched
1166
- self.yacc_value = src.matched
1167
- return :tGVAR
1168
- elsif src.scan(/\$[~*$?!@\/\\;,.=:<>\"]|\$-\w?/) then
1169
- self.lex_state = :expr_end
1170
- self.yacc_value = src.matched
1171
- return :tGVAR
1172
- elsif src.scan(/\$([\&\`\'\+])/) then
1173
- self.lex_state = :expr_end
1174
- # Explicit reference to these vars as symbols...
1175
- if last_state == :expr_fname then
1176
- self.yacc_value = src.matched
1177
- return :tGVAR
1178
- else
1179
- self.yacc_value = src[1].to_sym
1180
- return :tBACK_REF
1181
- end
1182
- elsif src.scan(/\$([1-9]\d*)/) then
1183
- self.lex_state = :expr_end
1184
- if last_state == :expr_fname then
1185
- self.yacc_value = src.matched
1186
- return :tGVAR
1187
- else
1188
- self.yacc_value = src[1].to_i
1189
- return :tNTH_REF
1190
- end
1191
- elsif src.scan(/\$0/) then
1192
- self.lex_state = :expr_end
1193
- self.token = src.matched
1194
- return process_token(command_state)
1195
- elsif src.scan(/\$\W|\$\z/) then # TODO: remove?
1196
- self.lex_state = :expr_end
1197
- self.yacc_value = "$"
1198
- return "$"
1199
- elsif src.scan(/\$\w+/)
1200
- self.lex_state = :expr_end
1201
- self.token = src.matched
1202
- return process_token(command_state)
1203
- end
1204
- elsif src.check(/\_/) then
1205
- if src.beginning_of_line? && src.scan(/\__END__(\n|\Z)/) then
1206
- self.lineno = nil
1207
- return RubyLexer::EOF
1208
- elsif src.scan(/\_\w*/) then
1209
- self.token = src.matched
1210
- return process_token(command_state)
1211
- end
1212
- end
1213
- end # END OF CASE
1214
-
1215
- if src.scan(/\004|\032|\000/) || src.eos? then # ^D, ^Z, EOF
1216
- return RubyLexer::EOF
1217
- else # alpha check
1218
- if src.scan(/\W/) then
1219
- rb_compile_error "Invalid char #{src.matched.inspect} in expression"
1220
- end
1221
- end
1222
-
1223
- self.token = src.matched if self.src.scan(/\w+/)
1224
-
1225
- return process_token(command_state)
1226
- end
1227
- end
1228
-
1229
- def process_token(command_state)
1230
-
1231
- token << src.matched if token =~ /^\w/ && src.scan(/[\!\?](?!=)/)
1232
-
1233
- result = nil
1234
- last_state = lex_state
1235
-
1236
-
1237
- case token
1238
- when /^\$/ then
1239
- self.lex_state, result = :expr_end, :tGVAR
1240
- when /^@@/ then
1241
- self.lex_state, result = :expr_end, :tCVAR
1242
- when /^@/ then
1243
- self.lex_state, result = :expr_end, :tIVAR
1244
- else
1245
- if token =~ /[!?]$/ then
1246
- result = :tFID
1247
- else
1248
- if lex_state == :expr_fname then
1249
- # ident=, not =~ => == or followed by =>
1250
- # TODO test lexing of a=>b vs a==>b
1251
- if src.scan(/=(?:(?![~>=])|(?==>))/) then
1252
- result = :tIDENTIFIER
1253
- token << src.matched
1254
- end
1255
- end
1256
-
1257
- result ||= if token =~ /^[A-Z]/ then
1258
- :tCONSTANT
1259
- else
1260
- :tIDENTIFIER
1261
- end
1262
- end
1263
-
1264
- if (lex_state == :expr_beg && !command_state) || lex_state == :expr_arg || lex_state == :expr_cmdarg
1265
- colon = src.scan(/:/)
1266
-
1267
- if colon && src.peek(1) != ":"
1268
- src.unscan
1269
- self.lex_state = :expr_beg
1270
- src.scan(/:/)
1271
- self.yacc_value = [token, src.lineno]
1272
- return :tLABEL
1273
- end
1274
-
1275
- src.unscan if colon
1276
- end
1277
-
1278
- unless lex_state == :expr_dot then
1279
- # See if it is a reserved word.
1280
- keyword = RubyParser::Keyword.keyword token
1281
-
1282
- if keyword then
1283
- state = lex_state
1284
- self.lex_state = keyword.state
1285
- self.yacc_value = [token, src.lineno]
1286
-
1287
- if state == :expr_fname then
1288
- self.yacc_value = keyword.name
1289
- return keyword.id0
1290
- end
1291
-
1292
- if keyword.id0 == :kDO then
1293
- self.command_start = true
1294
- return :kDO_COND if cond.is_in_state
1295
- return :kDO_BLOCK if cmdarg.is_in_state && state != :expr_cmdarg
1296
- return :kDO_BLOCK if state == :expr_endarg
1297
- if defined?(@hack_expects_lambda) && @hack_expects_lambda
1298
- @hack_expects_lambda = false
1299
- return :kDO_LAMBDA
1300
- end
1301
- return :kDO
1302
- end
1303
-
1304
- return keyword.id0 if state == :expr_beg or state == :expr_value
1305
-
1306
- self.lex_state = :expr_beg if keyword.id0 != keyword.id1
1307
-
1308
- return keyword.id1
1309
- end
1310
- end
1311
-
1312
- if (lex_state == :expr_beg || lex_state == :expr_mid ||
1313
- lex_state == :expr_dot || lex_state == :expr_arg ||
1314
- lex_state == :expr_cmdarg) then
1315
- if command_state then
1316
- self.lex_state = :expr_cmdarg
1317
- else
1318
- self.lex_state = :expr_arg
1319
- end
1320
- else
1321
- self.lex_state = :expr_end
1322
- end
1323
- end
1324
-
1325
- self.yacc_value = token
1326
-
1327
-
1328
- self.lex_state = :expr_end if
1329
- last_state != :expr_dot && self.parser.env[token.to_sym] == :lvar
1330
-
1331
- return result
1332
- end
1333
-
1334
- def yylex_string # 23 lines
1335
- token = if lex_strterm[0] == :heredoc then
1336
- self.heredoc lex_strterm
1337
- else
1338
- self.parse_string lex_strterm
1339
- end
1340
-
1341
- if token == :tSTRING_END || token == :tREGEXP_END then
1342
- self.lineno = nil
1343
- self.lex_strterm = nil
1344
- self.lex_state = :expr_end
1345
- end
1346
-
1347
- return token
1348
- end
1349
- end