ruby_parser 3.13.1 → 3.15.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.
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # TODO: remove
2
3
 
3
4
  require "sexp"
4
5
  require "ruby_lexer"
@@ -6,13 +7,50 @@ require "timeout"
6
7
  require "rp_extensions"
7
8
  require "rp_stringscanner"
8
9
 
10
+ class Sexp
11
+ def check_line_numbers
12
+ raise "bad nil line for:\n%s" % [self.pretty_inspect] if nil_line?
13
+ raise "bad line number for:\n%s" % [self.pretty_inspect] unless
14
+ Integer === self.line &&
15
+ self.line >= 1 &&
16
+ self.line <= self.line_min
17
+ end
18
+
19
+ ##
20
+ # Returns the maximum line number of the children of self.
21
+
22
+ def line_min
23
+ @line_min ||= [self.deep_each.map(&:line).min, self.line].compact.min
24
+ end
25
+
26
+ def nil_line?
27
+ self.deep_each.map(&:line).any?(&:nil?)
28
+ end
29
+ end
30
+
9
31
  module RubyParserStuff
10
- VERSION = "3.13.1"
32
+ VERSION = "3.15.1"
11
33
 
12
34
  attr_accessor :lexer, :in_def, :in_single, :file
13
35
  attr_accessor :in_kwarg
14
36
  attr_reader :env, :comments
15
37
 
38
+ ##
39
+ # Canonicalize conditionals. Eg:
40
+ #
41
+ # not x ? a : b
42
+ #
43
+ # becomes:
44
+ #
45
+ # x ? b : a
46
+
47
+ attr_accessor :canonicalize_conditions
48
+
49
+ ##
50
+ # The last token type returned from #next_token
51
+
52
+ attr_accessor :last_token_type
53
+
16
54
  $good20 = []
17
55
 
18
56
  %w[
@@ -31,6 +69,28 @@ module RubyParserStuff
31
69
  end
32
70
  end
33
71
 
72
+ ##
73
+ # for pure ruby systems only
74
+
75
+ def do_parse
76
+ _racc_do_parse_rb(_racc_setup, false)
77
+ end if ENV["PURE_RUBY"] || ENV["CHECK_LINE_NUMS"]
78
+
79
+ if ENV["CHECK_LINE_NUMS"] then
80
+ def _racc_do_reduce arg, act
81
+ x = super
82
+
83
+ @racc_vstack.grep(Sexp).each do |sexp|
84
+ sexp.check_line_numbers
85
+ end
86
+ x
87
+ end
88
+ end
89
+
90
+ ARG_TYPES = [:arglist, :call_args, :array, :args].map { |k|
91
+ [k, true]
92
+ }.to_h
93
+
34
94
  has_enc = "".respond_to? :encoding
35
95
 
36
96
  # This is in sorted order of occurrence according to
@@ -48,85 +108,52 @@ module RubyParserStuff
48
108
  Encoding::EUC_JP
49
109
  ] if has_enc
50
110
 
51
- def syntax_error msg
52
- raise RubyParser::SyntaxError, msg
53
- end
111
+ JUMP_TYPE = [:return, :next, :break, :yield].map { |k| [k, true] }.to_h
54
112
 
55
- def arg_blk_pass node1, node2 # TODO: nuke
56
- node1 = s(:arglist, node1) unless [:arglist, :call_args, :array, :args].include? node1.sexp_type
57
- node1 << node2 if node2
58
- node1
59
- end
113
+ TAB_WIDTH = 8
60
114
 
61
- def arg_concat node1, node2 # TODO: nuke
62
- raise "huh" unless node2
63
- node1 << s(:splat, node2).compact
64
- node1
65
- end
115
+ def initialize(options = {})
116
+ super()
66
117
 
67
- def clean_mlhs sexp
68
- case sexp.sexp_type
69
- when :masgn then
70
- if sexp.size == 2 and sexp[1].sexp_type == :array then
71
- s(:masgn, *sexp[1].sexp_body.map { |sub| clean_mlhs sub })
72
- else
73
- debug20 5
74
- sexp
75
- end
76
- when :gasgn, :iasgn, :lasgn, :cvasgn then
77
- if sexp.size == 2 then
78
- sexp.last
79
- else
80
- debug20 7
81
- sexp # optional value
82
- end
83
- else
84
- raise "unsupported type: #{sexp.inspect}"
85
- end
86
- end
118
+ v = self.class.name[/2\d/]
119
+ raise "Bad Class name #{self.class}" unless v
87
120
 
88
- def block_var *args
89
- result = self.args args
90
- result.sexp_type = :masgn
91
- result
92
- end
121
+ self.lexer = RubyLexer.new v && v.to_i
122
+ self.lexer.parser = self
123
+ self.in_kwarg = false
93
124
 
94
- def array_to_hash array
95
- case array.sexp_type
96
- when :kwsplat then
97
- array
98
- else
99
- s(:hash, *array.sexp_body)
100
- end
125
+ @env = RubyParserStuff::Environment.new
126
+ @comments = []
127
+
128
+ @canonicalize_conditions = true
129
+
130
+ self.reset
101
131
  end
102
132
 
103
- def call_args args
104
- result = s(:call_args)
133
+ def arg_concat node1, node2 # TODO: nuke
134
+ raise "huh" unless node2
105
135
 
106
- args.each do |arg|
107
- case arg
108
- when Sexp then
109
- case arg.sexp_type
110
- when :array, :args, :call_args then # HACK? remove array at some point
111
- result.concat arg.sexp_body
112
- else
113
- result << arg
114
- end
115
- when Symbol then
116
- result << arg
117
- when ",", nil then
118
- # ignore
119
- else
120
- raise "unhandled: #{arg.inspect} in #{args.inspect}"
121
- end
122
- end
136
+ splat = s(:splat, node2)
137
+ splat.line node2.line
123
138
 
124
- result
139
+ node1 << splat
140
+ end
141
+
142
+ def argl x
143
+ x = s(:arglist, x) if x and x.sexp_type == :array
144
+ x
125
145
  end
126
146
 
127
147
  def args args
128
148
  result = s(:args)
129
149
 
150
+ ss = args.grep Sexp
151
+ if ss.empty? then
152
+ result.line lexer.lineno
153
+ else
154
+ result.line ss.first.line
155
+ end
156
+
130
157
  args.each do |arg|
131
158
  case arg
132
159
  when Sexp then
@@ -162,13 +189,28 @@ module RubyParserStuff
162
189
  result
163
190
  end
164
191
 
192
+ def array_to_hash array
193
+ case array.sexp_type
194
+ when :kwsplat then
195
+ array
196
+ else
197
+ s(:hash, *array.sexp_body).line array.line
198
+ end
199
+ end
200
+
165
201
  def aryset receiver, index
166
202
  index ||= s()
167
- s(:attrasgn, receiver, :"[]=", *index.sexp_body).compact # [].sexp_body => nil
203
+ l = receiver.line
204
+ result = s(:attrasgn, receiver, :"[]=",
205
+ *index.sexp_body).compact # [].sexp_body => nil
206
+ result.line = l
207
+ result
168
208
  end
169
209
 
170
210
  def assignable(lhs, value = nil)
171
211
  id = lhs.to_sym unless Sexp === lhs
212
+
213
+ raise "WTF" if Sexp === id
172
214
  id = id.to_sym if Sexp === id
173
215
 
174
216
  raise "write a test 1" if id.to_s =~ /^(?:self|nil|true|false|__LINE__|__FILE__)$/
@@ -197,11 +239,33 @@ module RubyParserStuff
197
239
 
198
240
  self.env[id] ||= :lvar if result.sexp_type == :lasgn
199
241
 
242
+ line = case lhs
243
+ when Sexp then
244
+ lhs.line
245
+ else
246
+ value && value.line || lexer.lineno
247
+ end
248
+
200
249
  result << value if value
250
+ result.line = line
201
251
 
202
252
  return result
203
253
  end
204
254
 
255
+ def backref_assign_error ref
256
+ # TODO: need a test for this... obviously
257
+ case ref.sexp_type
258
+ when :nth_ref then
259
+ raise "write a test 2"
260
+ raise SyntaxError, "Can't set variable %p" % ref.last
261
+ when :back_ref then
262
+ raise "write a test 3"
263
+ raise SyntaxError, "Can't set back reference %p" % ref.last
264
+ else
265
+ raise "Unknown backref type: #{ref.inspect}"
266
+ end
267
+ end
268
+
205
269
  def block_append(head, tail)
206
270
  return head if tail.nil?
207
271
  return tail if head.nil?
@@ -215,6 +279,69 @@ module RubyParserStuff
215
279
  head << tail
216
280
  end
217
281
 
282
+ def block_dup_check call_or_args, block
283
+ syntax_error "Both block arg and actual block given." if
284
+ block and call_or_args.block_pass?
285
+ end
286
+
287
+ def block_var *args
288
+ result = self.args args
289
+ result.sexp_type = :masgn
290
+ result
291
+ end
292
+
293
+ def call_args args
294
+ result = s(:call_args)
295
+
296
+ a = args.grep(Sexp).first
297
+ if a then
298
+ result.line a.line
299
+ else
300
+ result.line lexer.lineno
301
+ end
302
+
303
+ args.each do |arg|
304
+ case arg
305
+ when Sexp then
306
+ case arg.sexp_type
307
+ when :array, :args, :call_args then # HACK? remove array at some point
308
+ result.concat arg.sexp_body
309
+ else
310
+ result << arg
311
+ end
312
+ when Symbol then
313
+ result << arg
314
+ when ",", nil then
315
+ # ignore
316
+ else
317
+ raise "unhandled: #{arg.inspect} in #{args.inspect}"
318
+ end
319
+ end
320
+
321
+ result
322
+ end
323
+
324
+ def clean_mlhs sexp
325
+ case sexp.sexp_type
326
+ when :masgn then
327
+ if sexp.size == 2 and sexp[1].sexp_type == :array then
328
+ s(:masgn, *sexp[1].sexp_body.map { |sub| clean_mlhs sub })
329
+ else
330
+ debug20 5
331
+ sexp
332
+ end
333
+ when :gasgn, :iasgn, :lasgn, :cvasgn then
334
+ if sexp.size == 2 then
335
+ sexp.last
336
+ else
337
+ debug20 7
338
+ sexp # optional value
339
+ end
340
+ else
341
+ raise "unsupported type: #{sexp.inspect}"
342
+ end
343
+ end
344
+
218
345
  def cond node
219
346
  return nil if node.nil?
220
347
  node = value_expr node
@@ -222,56 +349,113 @@ module RubyParserStuff
222
349
  case node.sexp_type
223
350
  when :lit then
224
351
  if Regexp === node.last then
225
- return s(:match, node)
352
+ s(:match, node)
226
353
  else
227
- return node
354
+ node
228
355
  end
229
356
  when :and then
230
- return s(:and, cond(node[1]), cond(node[2]))
357
+ _, lhs, rhs = node
358
+ s(:and, cond(lhs), cond(rhs))
231
359
  when :or then
232
- return s(:or, cond(node[1]), cond(node[2]))
360
+ _, lhs, rhs = node
361
+ s(:or, cond(lhs), cond(rhs))
233
362
  when :dot2 then
234
363
  label = "flip#{node.hash}"
235
364
  env[label] = :lvar
236
365
  _, lhs, rhs = node
237
- return s(:flip2, lhs, rhs)
366
+ s(:flip2, lhs, rhs) # TODO: recurse?
238
367
  when :dot3 then
239
368
  label = "flip#{node.hash}"
240
369
  env[label] = :lvar
241
370
  _, lhs, rhs = node
242
- return s(:flip3, lhs, rhs)
371
+ s(:flip3, lhs, rhs)
243
372
  else
244
- return node
245
- end
373
+ node
374
+ end.line node.line
246
375
  end
247
376
 
248
- ##
249
- # for pure ruby systems only
377
+ def dedent sexp
378
+ dedent_count = dedent_size sexp
250
379
 
251
- def do_parse
252
- _racc_do_parse_rb(_racc_setup, false)
253
- end if ENV['PURE_RUBY']
380
+ skip_one = false
381
+ sexp.map { |obj|
382
+ case obj
383
+ when Symbol then
384
+ obj
385
+ when String then
386
+ obj.lines.map { |l| remove_whitespace_width l, dedent_count }.join
387
+ when Sexp then
388
+ case obj.sexp_type
389
+ when :evstr then
390
+ skip_one = true
391
+ obj
392
+ when :str then
393
+ _, str = obj
394
+ str = if skip_one then
395
+ skip_one = false
396
+ s1, *rest = str.lines
397
+ s1 + rest.map { |l| remove_whitespace_width l, dedent_count }.join
398
+ else
399
+ str.lines.map { |l| remove_whitespace_width l, dedent_count }.join
400
+ end
254
401
 
255
- def new_match lhs, rhs
256
- if lhs then
257
- case lhs.sexp_type
258
- when :dregx, :dregx_once then
259
- return s(:match2, lhs, rhs).line(lhs.line)
260
- when :lit then
261
- return s(:match2, lhs, rhs).line(lhs.line) if Regexp === lhs.last
402
+ s(:str, str).line obj.line
403
+ else
404
+ warn "unprocessed sexp %p" % [obj]
405
+ end
406
+ else
407
+ warn "unprocessed: %p" % [obj]
262
408
  end
263
- end
409
+ }
410
+ end
264
411
 
265
- if rhs then
266
- case rhs.sexp_type
267
- when :dregx, :dregx_once then
268
- return s(:match3, rhs, lhs).line(lhs.line)
269
- when :lit then
270
- return s(:match3, rhs, lhs).line(lhs.line) if Regexp === rhs.last
412
+ def dedent_size sexp
413
+ skip_one = false
414
+ sexp.flat_map { |s|
415
+ case s
416
+ when Symbol then
417
+ next
418
+ when String then
419
+ s.lines
420
+ when Sexp then
421
+ case s.sexp_type
422
+ when :evstr then
423
+ skip_one = true
424
+ next
425
+ when :str then
426
+ _, str = s
427
+ lines = str.lines
428
+ if skip_one then
429
+ skip_one = false
430
+ lines.shift
431
+ end
432
+ lines
433
+ else
434
+ warn "unprocessed sexp %p" % [s]
435
+ end
436
+ else
437
+ warn "unprocessed: %p" % [s]
438
+ end.map { |l| whitespace_width l[/^[ \t]*/] }
439
+ }.compact.min
440
+ end
441
+
442
+ def dedent_string string, width
443
+ characters_skipped = 0
444
+ indentation_skipped = 0
445
+
446
+ string.chars.each do |char|
447
+ break if indentation_skipped >= width
448
+ if char == " "
449
+ characters_skipped += 1
450
+ indentation_skipped += 1
451
+ elsif char == "\t"
452
+ proposed = TAB_WIDTH * (indentation_skipped / TAB_WIDTH + 1)
453
+ break if proposed > width
454
+ characters_skipped += 1
455
+ indentation_skipped = proposed
271
456
  end
272
457
  end
273
-
274
- return new_call(lhs, :"=~", argl(rhs)).line(lhs.line)
458
+ string[characters_skipped..-1]
275
459
  end
276
460
 
277
461
  def gettable(id)
@@ -303,33 +487,94 @@ module RubyParserStuff
303
487
  result
304
488
  end
305
489
 
490
+ def hack_encoding str, extra = nil
491
+ encodings = ENCODING_ORDER.dup
492
+ encodings.unshift(extra) unless extra.nil?
493
+
494
+ # terrible, horrible, no good, very bad, last ditch effort.
495
+ encodings.each do |enc|
496
+ begin
497
+ str.force_encoding enc
498
+ if str.valid_encoding? then
499
+ str.encode! Encoding::UTF_8
500
+ break
501
+ end
502
+ rescue ArgumentError # unknown encoding name
503
+ # do nothing
504
+ rescue Encoding::InvalidByteSequenceError
505
+ # do nothing
506
+ rescue Encoding::UndefinedConversionError
507
+ # do nothing
508
+ end
509
+ end
510
+
511
+ # no amount of pain is enough for you.
512
+ raise "Bad encoding. Need a magic encoding comment." unless
513
+ str.encoding.name == "UTF-8"
514
+ end
515
+
306
516
  ##
307
- # Canonicalize conditionals. Eg:
308
- #
309
- # not x ? a : b
517
+ # Returns a UTF-8 encoded string after processing BOMs and magic
518
+ # encoding comments.
310
519
  #
311
- # becomes:
520
+ # Holy crap... ok. Here goes:
312
521
  #
313
- # x ? b : a
522
+ # Ruby's file handling and encoding support is insane. We need to be
523
+ # able to lex a file. The lexer file is explicitly UTF-8 to make
524
+ # things cleaner. This allows us to deal with extended chars in
525
+ # class and method names. In order to do this, we need to encode all
526
+ # input source files as UTF-8. First, we look for a UTF-8 BOM by
527
+ # looking at the first line while forcing its encoding to
528
+ # ASCII-8BIT. If we find a BOM, we strip it and set the expected
529
+ # encoding to UTF-8. Then, we search for a magic encoding comment.
530
+ # If found, it overrides the BOM. Finally, we force the encoding of
531
+ # the input string to whatever was found, and then encode that to
532
+ # UTF-8 for compatibility with the lexer.
314
533
 
315
- attr_accessor :canonicalize_conditions
534
+ def handle_encoding str
535
+ str = str.dup
536
+ has_enc = str.respond_to? :encoding
537
+ encoding = nil
316
538
 
317
- def initialize(options = {})
318
- super()
539
+ header = str.each_line.first(2)
540
+ header.map! { |s| s.force_encoding "ASCII-8BIT" } if has_enc
319
541
 
320
- v = self.class.name[/2\d/]
321
- raise "Bad Class name #{self.class}" unless v
542
+ first = header.first || ""
543
+ encoding, str = "utf-8", str.b[3..-1] if first =~ /\A\xEF\xBB\xBF/
322
544
 
323
- self.lexer = RubyLexer.new v && v.to_i
324
- self.lexer.parser = self
325
- self.in_kwarg = false
545
+ encoding = $1.strip if header.find { |s|
546
+ s[/^#.*?-\*-.*?coding:\s*([^ ;]+).*?-\*-/, 1] ||
547
+ s[/^#.*(?:en)?coding(?:\s*[:=])\s*([\w-]+)/, 1]
548
+ }
326
549
 
327
- @env = RubyParserStuff::Environment.new
328
- @comments = []
550
+ if encoding then
551
+ if has_enc then
552
+ encoding.sub!(/utf-8-.+$/, "utf-8") # HACK for stupid emacs formats
553
+ hack_encoding str, encoding
554
+ else
555
+ warn "Skipping magic encoding comment"
556
+ end
557
+ else
558
+ # nothing specified... ugh. try to encode as utf-8
559
+ hack_encoding str if has_enc
560
+ end
329
561
 
330
- @canonicalize_conditions = true
562
+ str
563
+ end
331
564
 
332
- self.reset
565
+ def invert_block_call val
566
+ ret, iter = val
567
+ type, call = ret
568
+
569
+ iter.insert 1, call
570
+
571
+ ret = s(type).line ret.line
572
+
573
+ [iter, ret]
574
+ end
575
+
576
+ def inverted? val
577
+ JUMP_TYPE[val[0].sexp_type]
333
578
  end
334
579
 
335
580
  def list_append list, item # TODO: nuke me *sigh*
@@ -350,12 +595,14 @@ module RubyParserStuff
350
595
 
351
596
  htype, ttype = head.sexp_type, tail.sexp_type
352
597
 
353
- head = s(:dstr, '', head) if htype == :evstr
598
+ head = s(:dstr, "", head).line head.line if htype == :evstr
354
599
 
355
600
  case ttype
356
601
  when :str then
357
602
  if htype == :str
358
- head.last << tail.last
603
+ a, b = head.last, tail.last
604
+ b = b.dup.force_encoding a.encoding unless Encoding.compatible?(a, b)
605
+ a << b
359
606
  elsif htype == :dstr and head.size == 2 then
360
607
  head.last << tail.last
361
608
  else
@@ -369,15 +616,15 @@ module RubyParserStuff
369
616
  head.line = lineno
370
617
  else
371
618
  tail.sexp_type = :array
372
- tail[1] = s(:str, tail[1])
373
- tail.delete_at 1 if tail[1] == s(:str, '')
619
+ tail[1] = s(:str, tail[1]).line tail.line
620
+ tail.delete_at 1 if tail[1] == s(:str, "")
374
621
 
375
622
  head.push(*tail.sexp_body)
376
623
  end
377
624
  when :evstr then
378
625
  if htype == :str then
379
626
  f, l = head.file, head.line
380
- head = s(:dstr, *head.sexp_body)
627
+ head = s(:dstr, *head.sexp_body).line head.line
381
628
  head.file = f
382
629
  head.line = l
383
630
  end
@@ -408,12 +655,15 @@ module RubyParserStuff
408
655
  node = rhs
409
656
  end
410
657
 
411
- node[2] = s(type, rhs, right)
658
+ node.pop
659
+ node << s(type, rhs, right).line(rhs.line)
412
660
 
413
661
  return left
414
662
  end
415
663
 
416
- return s(type, left, right)
664
+ result = s(type, left, right)
665
+ result.line left.line if left.line
666
+ result
417
667
  end
418
668
 
419
669
  def new_aref val
@@ -422,6 +672,49 @@ module RubyParserStuff
422
672
  new_call val[0], :"[]", val[2]
423
673
  end
424
674
 
675
+ def new_assign lhs, rhs
676
+ return nil unless lhs
677
+
678
+ rhs = value_expr rhs
679
+
680
+ case lhs.sexp_type
681
+ when :lasgn, :iasgn, :cdecl, :cvdecl, :gasgn, :cvasgn, :attrasgn, :safe_attrasgn then
682
+ lhs << rhs
683
+ when :const then
684
+ lhs.sexp_type = :cdecl
685
+ lhs << rhs
686
+ else
687
+ raise "unknown lhs #{lhs.inspect} w/ #{rhs.inspect}"
688
+ end
689
+
690
+ lhs
691
+ end
692
+
693
+ def new_attrasgn recv, meth, call_op = :"."
694
+ meth = :"#{meth}="
695
+
696
+ result = case call_op.to_sym
697
+ when :"."
698
+ s(:attrasgn, recv, meth)
699
+ when :"&."
700
+ s(:safe_attrasgn, recv, meth)
701
+ else
702
+ raise "unknown call operator: `#{type.inspect}`"
703
+ end
704
+
705
+ result.line = recv.line
706
+ result
707
+ end
708
+
709
+ def new_begin val
710
+ _, lineno, body, _ = val
711
+
712
+ result = body ? s(:begin, body) : s(:nil)
713
+ result.line lineno
714
+
715
+ result
716
+ end
717
+
425
718
  def new_body val
426
719
  body, resbody, elsebody, ensurebody = val
427
720
 
@@ -445,43 +738,27 @@ module RubyParserStuff
445
738
 
446
739
  if elsebody and not resbody then
447
740
  warning("else without rescue is useless")
448
- result = s(:begin, result) if result
741
+ result = s(:begin, result).line result.line if result
449
742
  result = block_append(result, elsebody)
450
743
  end
451
744
 
452
- result = s(:ensure, result, ensurebody).compact if ensurebody
745
+ if ensurebody
746
+ lineno = (result || ensurebody).line
747
+ result = s(:ensure, result, ensurebody).compact.line lineno
748
+ end
453
749
 
454
750
  result
455
751
  end
456
752
 
457
753
  def new_brace_body args, body, lineno
458
- new_iter(nil, args, body).line(lineno)
754
+ new_iter(nil, args, body).line lineno
459
755
  end
460
756
 
461
- def argl x
462
- x = s(:arglist, x) if x and x.sexp_type == :array
463
- x
464
- end
465
-
466
- def backref_assign_error ref
467
- # TODO: need a test for this... obviously
468
- case ref.sexp_type
469
- when :nth_ref then
470
- raise "write a test 2"
471
- raise SyntaxError, "Can't set variable %p" % ref.last
472
- when :back_ref then
473
- raise "write a test 3"
474
- raise SyntaxError, "Can't set back reference %p" % ref.last
475
- else
476
- raise "Unknown backref type: #{ref.inspect}"
477
- end
478
- end
479
-
480
- def new_call recv, meth, args = nil, call_op = :'.'
757
+ def new_call recv, meth, args = nil, call_op = :"."
481
758
  result = case call_op.to_sym
482
- when :'.'
759
+ when :"."
483
760
  s(:call, recv, meth)
484
- when :'&.'
761
+ when :"&."
485
762
  s(:safe_call, recv, meth)
486
763
  else
487
764
  raise "unknown call operator: `#{type.inspect}`"
@@ -491,32 +768,17 @@ module RubyParserStuff
491
768
  # TODO: need a test with f(&b) { } to produce warning
492
769
 
493
770
  if args
494
- if [:arglist, :args, :array, :call_args].include? args.sexp_type
771
+ if ARG_TYPES[args.sexp_type] then
495
772
  result.concat args.sexp_body
496
773
  else
497
774
  result << args
498
775
  end
499
776
  end
500
777
 
501
- line = result.grep(Sexp).map(&:line).compact.min
502
- result.line = line if line
503
-
504
- result
505
- end
506
-
507
- def new_attrasgn recv, meth, call_op
508
- meth = :"#{meth}="
509
-
510
- result = case call_op.to_sym
511
- when :'.'
512
- s(:attrasgn, recv, meth)
513
- when :'&.'
514
- s(:safe_attrasgn, recv, meth)
515
- else
516
- raise "unknown call operator: `#{type.inspect}`"
517
- end
778
+ # line = result.grep(Sexp).map(&:line).compact.min
779
+ result.line = recv.line if recv
780
+ result.line ||= lexer.lineno
518
781
 
519
- result.line = recv.line
520
782
  result
521
783
  end
522
784
 
@@ -565,11 +827,29 @@ module RubyParserStuff
565
827
  result
566
828
  end
567
829
 
830
+ def new_const_op_asgn val
831
+ lhs, asgn_op, rhs = val[0], val[1].to_sym, val[2]
832
+
833
+ result = case asgn_op
834
+ when :"||" then
835
+ s(:op_asgn_or, lhs, rhs)
836
+ when :"&&" then
837
+ s(:op_asgn_and, lhs, rhs)
838
+ else
839
+ s(:op_asgn, lhs, asgn_op, rhs)
840
+ end
841
+
842
+ result.line = lhs.line
843
+ result
844
+ end
845
+
568
846
  def new_defn val
569
- (_, line), (name, _), _, args, body, * = val
570
- body ||= s(:nil)
847
+ (_, line), name, _, args, body, nil_body_line, * = val
848
+ body ||= s(:nil).line nil_body_line
571
849
 
572
- result = s(:defn, name.to_sym, args)
850
+ args.line line
851
+
852
+ result = s(:defn, name.to_sym, args).line line
573
853
 
574
854
  if body then
575
855
  if body.sexp_type == :block then
@@ -579,19 +859,23 @@ module RubyParserStuff
579
859
  end
580
860
  end
581
861
 
582
- args.line line
583
- result.line = line
584
862
  result.comments = self.comments.pop
585
863
 
586
864
  result
587
865
  end
588
866
 
589
867
  def new_defs val
590
- recv, (name, _line), args, body = val[1], val[4], val[6], val[7]
591
- body ||= s(:nil)
868
+ _, recv, _, _, name, (_in_def, line), args, body, _ = val
869
+
870
+ body ||= s(:nil).line line
871
+
872
+ args.line line
592
873
 
593
874
  result = s(:defs, recv, name.to_sym, args)
594
875
 
876
+ # TODO: remove_begin
877
+ # TODO: reduce_nodes
878
+
595
879
  if body then
596
880
  if body.sexp_type == :block then
597
881
  result.push(*body.sexp_body)
@@ -616,7 +900,9 @@ module RubyParserStuff
616
900
  end
617
901
 
618
902
  def new_hash val
619
- s(:hash, *val[2].values).line(val[1])
903
+ _, line, assocs = val
904
+
905
+ s(:hash).line(line).concat assocs.values
620
906
  end
621
907
 
622
908
  def new_if c, t, f
@@ -637,27 +923,59 @@ module RubyParserStuff
637
923
  result << args
638
924
  result << body if body
639
925
 
640
- args.sexp_type = :args unless args == 0
926
+ result.line call.line if call
641
927
 
642
- result
643
- end
928
+ unless args == 0 then
929
+ args.line call.line if call
930
+ args.sexp_type = :args
931
+ end
644
932
 
645
- def new_masgn_arg rhs, wrap = false
646
- rhs = value_expr(rhs)
647
- rhs = s(:to_ary, rhs) if wrap # HACK: could be array if lhs isn't right
648
- rhs
933
+ result
649
934
  end
650
935
 
651
936
  def new_masgn lhs, rhs, wrap = false
652
937
  _, ary = lhs
653
938
 
939
+ line = rhs.line
654
940
  rhs = value_expr(rhs)
655
941
  rhs = ary ? s(:to_ary, rhs) : s(:array, rhs) if wrap
942
+ rhs.line line if wrap
656
943
 
657
944
  lhs.delete_at 1 if ary.nil?
658
945
  lhs << rhs
659
946
 
660
- lhs
947
+ lhs
948
+ end
949
+
950
+ def new_masgn_arg rhs, wrap = false
951
+ rhs = value_expr(rhs)
952
+ # HACK: could be array if lhs isn't right
953
+ rhs = s(:to_ary, rhs).line rhs.line if wrap
954
+ rhs
955
+ end
956
+
957
+ def new_match lhs, rhs
958
+ if lhs then
959
+ case lhs.sexp_type
960
+ when :dregx, :dregx_once then
961
+ # TODO: no test coverage
962
+ return s(:match2, lhs, rhs).line(lhs.line)
963
+ when :lit then
964
+ return s(:match2, lhs, rhs).line(lhs.line) if Regexp === lhs.last
965
+ end
966
+ end
967
+
968
+ if rhs then
969
+ case rhs.sexp_type
970
+ when :dregx, :dregx_once then
971
+ # TODO: no test coverage
972
+ return s(:match3, rhs, lhs).line(lhs.line)
973
+ when :lit then
974
+ return s(:match3, rhs, lhs).line(lhs.line) if Regexp === rhs.last
975
+ end
976
+ end
977
+
978
+ new_call(lhs, :"=~", argl(rhs)).line lhs.line
661
979
  end
662
980
 
663
981
  def new_module val
@@ -680,37 +998,30 @@ module RubyParserStuff
680
998
 
681
999
  def new_op_asgn val
682
1000
  lhs, asgn_op, arg = val[0], val[1].to_sym, val[2]
683
- name = lhs.value
1001
+ name = gettable(lhs.value).line lhs.line
684
1002
  arg = remove_begin(arg)
685
1003
  result = case asgn_op # REFACTOR
686
1004
  when :"||" then
687
1005
  lhs << arg
688
- s(:op_asgn_or, self.gettable(name), lhs)
1006
+ s(:op_asgn_or, name, lhs)
689
1007
  when :"&&" then
690
1008
  lhs << arg
691
- s(:op_asgn_and, self.gettable(name), lhs)
1009
+ s(:op_asgn_and, name, lhs)
692
1010
  else
693
- # TODO: why [2] ?
694
- lhs[2] = new_call(self.gettable(name), asgn_op, argl(arg))
1011
+ lhs << new_call(name, asgn_op, argl(arg))
695
1012
  lhs
696
1013
  end
697
1014
  result.line = lhs.line
698
1015
  result
699
1016
  end
700
1017
 
701
- def new_const_op_asgn val
702
- lhs, asgn_op, rhs = val[0], val[1].to_sym, val[2]
1018
+ def new_op_asgn1 val
1019
+ lhs, _, args, _, op, rhs = val
703
1020
 
704
- result = case asgn_op
705
- when :"||" then
706
- s(:op_asgn_or, lhs, rhs)
707
- when :"&&" then
708
- s(:op_asgn_and, lhs, rhs)
709
- else
710
- s(:op_asgn, lhs, asgn_op, rhs)
711
- end
1021
+ args.sexp_type = :arglist if args
712
1022
 
713
- result.line = lhs.line
1023
+ result = s(:op_asgn1, lhs, args, op.to_sym, rhs)
1024
+ result.line lhs.line
714
1025
  result
715
1026
  end
716
1027
 
@@ -719,9 +1030,9 @@ module RubyParserStuff
719
1030
  meth = :"#{meth}="
720
1031
 
721
1032
  result = case call_op.to_sym
722
- when :'.'
1033
+ when :"."
723
1034
  s(:op_asgn2, recv, meth, op.to_sym, arg)
724
- when :'&.'
1035
+ when :"&."
725
1036
  s(:safe_op_asgn2, recv, meth, op.to_sym, arg)
726
1037
  else
727
1038
  raise "unknown call operator: `#{type.inspect}`"
@@ -731,21 +1042,49 @@ module RubyParserStuff
731
1042
  result
732
1043
  end
733
1044
 
1045
+ def new_qsym_list
1046
+ result = s(:array).line lexer.lineno
1047
+ self.lexer.fixup_lineno
1048
+ result
1049
+ end
1050
+
1051
+ def new_qsym_list_entry val
1052
+ _, str, _ = val
1053
+ result = s(:lit, str.to_sym).line lexer.lineno
1054
+ self.lexer.fixup_lineno
1055
+ result
1056
+ end
1057
+
1058
+ def new_qword_list
1059
+ result = s(:array).line lexer.lineno
1060
+ self.lexer.fixup_lineno
1061
+ result
1062
+ end
1063
+
1064
+ def new_qword_list_entry val
1065
+ _, str, _ = val
1066
+ str.force_encoding("ASCII-8BIT") unless str.valid_encoding?
1067
+ result = s(:str, str).line lexer.lineno # TODO: problematic? grab from parser
1068
+ self.lexer.fixup_lineno
1069
+ result
1070
+ end
1071
+
734
1072
  def new_regexp val
735
- node = val[1] || s(:str, '')
736
- options = val[2]
1073
+ _, node, options = val
1074
+
1075
+ node ||= s(:str, "").line lexer.lineno
737
1076
 
738
1077
  o, k = 0, nil
739
1078
  options.split(//).uniq.each do |c| # FIX: this has a better home
740
1079
  v = {
741
- 'x' => Regexp::EXTENDED,
742
- 'i' => Regexp::IGNORECASE,
743
- 'm' => Regexp::MULTILINE,
744
- 'o' => Regexp::ONCE,
745
- 'n' => Regexp::ENC_NONE,
746
- 'e' => Regexp::ENC_EUC,
747
- 's' => Regexp::ENC_SJIS,
748
- 'u' => Regexp::ENC_UTF8,
1080
+ "x" => Regexp::EXTENDED,
1081
+ "i" => Regexp::IGNORECASE,
1082
+ "m" => Regexp::MULTILINE,
1083
+ "o" => Regexp::ONCE,
1084
+ "n" => Regexp::ENC_NONE,
1085
+ "e" => Regexp::ENC_EUC,
1086
+ "s" => Regexp::ENC_SJIS,
1087
+ "u" => Regexp::ENC_UTF8,
749
1088
  }[c]
750
1089
  raise "unknown regexp option: #{c}" unless v
751
1090
  o += v
@@ -778,7 +1117,7 @@ module RubyParserStuff
778
1117
  end
779
1118
  node << o if o and o != 0
780
1119
  else
781
- node = s(:dregx, '', node);
1120
+ node = s(:dregx, "", node).line node.line
782
1121
  node.sexp_type = :dregx_once if options =~ /o/
783
1122
  node << o if o and o != 0
784
1123
  end
@@ -786,19 +1125,20 @@ module RubyParserStuff
786
1125
  node
787
1126
  end
788
1127
 
789
- def new_rescue body, resbody
790
- s(:rescue, body, resbody)
791
- end
792
-
793
1128
  def new_resbody cond, body
794
1129
  if body && body.sexp_type == :block then
795
1130
  body.shift # remove block and splat it in directly
796
1131
  else
797
1132
  body = [body]
798
1133
  end
1134
+
799
1135
  s(:resbody, cond, *body).line cond.line
800
1136
  end
801
1137
 
1138
+ def new_rescue body, resbody
1139
+ s(:rescue, body, resbody).line body.line
1140
+ end
1141
+
802
1142
  def new_sclass val
803
1143
  recv, in_def, in_single, body = val[3], val[4], val[6], val[7]
804
1144
 
@@ -819,63 +1159,36 @@ module RubyParserStuff
819
1159
  end
820
1160
 
821
1161
  def new_string val
822
- str = val[0]
1162
+ str, = val
823
1163
  str.force_encoding("UTF-8")
1164
+ # TODO: remove:
824
1165
  str.force_encoding("ASCII-8BIT") unless str.valid_encoding?
825
- result = s(:str, str)
1166
+ result = s(:str, str).line lexer.lineno
826
1167
  self.lexer.fixup_lineno str.count("\n")
827
1168
  result
828
1169
  end
829
1170
 
830
- def new_qword_list_entry val
831
- str = val[1]
832
- str.force_encoding("ASCII-8BIT") unless str.valid_encoding?
833
- result = s(:str, str)
834
- self.lexer.fixup_lineno
835
- result
836
- end
837
-
838
- def new_qword_list
839
- result = s(:array)
840
- self.lexer.fixup_lineno
841
- result
842
- end
843
-
844
- def new_word_list
845
- result = s(:array)
846
- self.lexer.fixup_lineno
847
- result
848
- end
849
-
850
- def new_word_list_entry val
851
- result = val[1].sexp_type == :evstr ? s(:dstr, "", val[1]) : val[1]
852
- self.lexer.fixup_lineno
853
- result
854
- end
855
-
856
- def new_qsym_list
857
- result = s(:array)
858
- self.lexer.fixup_lineno
859
- result
860
- end
861
-
862
- def new_qsym_list_entry val
863
- result = s(:lit, val[1].to_sym)
864
- self.lexer.fixup_lineno
865
- result
1171
+ def new_super args
1172
+ if args && args.node_type == :block_pass then
1173
+ s(:super, args).line args.line
1174
+ else
1175
+ args ||= s(:arglist).line lexer.lineno
1176
+ s(:super, *args.sexp_body).line args.line
1177
+ end
866
1178
  end
867
1179
 
868
1180
  def new_symbol_list
869
- result = s(:array)
1181
+ result = s(:array).line lexer.lineno
870
1182
  self.lexer.fixup_lineno
871
1183
  result
872
1184
  end
873
1185
 
874
1186
  def new_symbol_list_entry val
875
- _list, sym, _nil = val # TODO: use _list
876
- result = val[1]
1187
+ _, sym, _ = val
1188
+
1189
+ sym ||= s(:str, "")
877
1190
 
878
- result ||= s(:str, "")
1191
+ line = lexer.lineno
879
1192
 
880
1193
  case sym.sexp_type
881
1194
  when :dstr then
@@ -883,26 +1196,21 @@ module RubyParserStuff
883
1196
  when :str then
884
1197
  sym = s(:lit, sym.last.to_sym)
885
1198
  else
886
- sym = s(:dsym, "", sym || s(:str, ""))
1199
+ sym = s(:dsym, "", sym || s(:str, "").line(line))
887
1200
  end
1201
+
1202
+ sym.line line
1203
+
888
1204
  self.lexer.fixup_lineno
889
- sym
890
- end
891
1205
 
892
- def new_super args
893
- if args && args.node_type == :block_pass then
894
- s(:super, args)
895
- else
896
- args ||= s(:arglist)
897
- s(:super, *args.sexp_body)
898
- end
1206
+ sym
899
1207
  end
900
1208
 
901
1209
  def new_undef n, m = nil
902
1210
  if m then
903
- block_append(n, s(:undef, m))
1211
+ block_append(n, s(:undef, m).line(m.line))
904
1212
  else
905
- s(:undef, n)
1213
+ s(:undef, n).line n.line
906
1214
  end
907
1215
  end
908
1216
 
@@ -935,20 +1243,36 @@ module RubyParserStuff
935
1243
  new_until_or_while :while, block, expr, pre
936
1244
  end
937
1245
 
938
- def new_xstring str
939
- if str then
940
- case str.sexp_type
1246
+ def new_word_list
1247
+ result = s(:array).line lexer.lineno
1248
+ self.lexer.fixup_lineno
1249
+ result
1250
+ end
1251
+
1252
+ def new_word_list_entry val
1253
+ _, word, _ = val
1254
+ result = word.sexp_type == :evstr ? s(:dstr, "", word).line(word.line) : word
1255
+ self.lexer.fixup_lineno
1256
+ result
1257
+ end
1258
+
1259
+ def new_xstring val
1260
+ _, node = val
1261
+
1262
+ node ||= s(:str, "").line lexer.lineno
1263
+
1264
+ if node then
1265
+ case node.sexp_type
941
1266
  when :str
942
- str.sexp_type = :xstr
1267
+ node.sexp_type = :xstr
943
1268
  when :dstr
944
- str.sexp_type = :dxstr
1269
+ node.sexp_type = :dxstr
945
1270
  else
946
- str = s(:dxstr, '', str)
1271
+ node = s(:dxstr, "", node).line node.line
947
1272
  end
948
- str
949
- else
950
- s(:xstr, '')
951
1273
  end
1274
+
1275
+ node
952
1276
  end
953
1277
 
954
1278
  def new_yield args = nil
@@ -957,113 +1281,32 @@ module RubyParserStuff
957
1281
  raise SyntaxError, "Block argument should not be given." if
958
1282
  args && args.node_type == :block_pass
959
1283
 
960
- args ||= s(:arglist)
1284
+ args ||= s(:arglist).line lexer.lineno
961
1285
 
962
1286
  args.sexp_type = :arglist if [:call_args, :array].include? args.sexp_type
963
- args = s(:arglist, args) unless args.sexp_type == :arglist
1287
+ args = s(:arglist, args).line args.line unless args.sexp_type == :arglist
964
1288
 
965
- return s(:yield, *args.sexp_body)
1289
+ s(:yield, *args.sexp_body).line args.line
966
1290
  end
967
1291
 
968
1292
  def next_token
969
1293
  token = self.lexer.next_token
970
1294
 
971
1295
  if token and token.first != RubyLexer::EOF then
1296
+ self.last_token_type = token
972
1297
  return token
973
1298
  else
974
- return [false, '$end']
975
- end
976
- end
977
-
978
- def new_assign lhs, rhs
979
- return nil unless lhs
980
-
981
- rhs = value_expr rhs
982
-
983
- case lhs.sexp_type
984
- when :lasgn, :iasgn, :cdecl, :cvdecl, :gasgn, :cvasgn, :attrasgn, :safe_attrasgn then
985
- lhs << rhs
986
- when :const then
987
- lhs.sexp_type = :cdecl
988
- lhs << rhs
989
- else
990
- raise "unknown lhs #{lhs.inspect} w/ #{rhs.inspect}"
991
- end
992
-
993
- lhs
994
- end
995
-
996
- ##
997
- # Returns a UTF-8 encoded string after processing BOMs and magic
998
- # encoding comments.
999
- #
1000
- # Holy crap... ok. Here goes:
1001
- #
1002
- # Ruby's file handling and encoding support is insane. We need to be
1003
- # able to lex a file. The lexer file is explicitly UTF-8 to make
1004
- # things cleaner. This allows us to deal with extended chars in
1005
- # class and method names. In order to do this, we need to encode all
1006
- # input source files as UTF-8. First, we look for a UTF-8 BOM by
1007
- # looking at the first line while forcing its encoding to
1008
- # ASCII-8BIT. If we find a BOM, we strip it and set the expected
1009
- # encoding to UTF-8. Then, we search for a magic encoding comment.
1010
- # If found, it overrides the BOM. Finally, we force the encoding of
1011
- # the input string to whatever was found, and then encode that to
1012
- # UTF-8 for compatibility with the lexer.
1013
-
1014
- def handle_encoding str
1015
- str = str.dup
1016
- has_enc = str.respond_to? :encoding
1017
- encoding = nil
1018
-
1019
- header = str.each_line.first(2)
1020
- header.map! { |s| s.force_encoding "ASCII-8BIT" } if has_enc
1021
-
1022
- first = header.first || ""
1023
- encoding, str = "utf-8", str[3..-1] if first =~ /\A\xEF\xBB\xBF/
1024
-
1025
- encoding = $1.strip if header.find { |s|
1026
- s[/^#.*?-\*-.*?coding:\s*([^ ;]+).*?-\*-/, 1] ||
1027
- s[/^#.*(?:en)?coding(?:\s*[:=])\s*([\w-]+)/, 1]
1028
- }
1029
-
1030
- if encoding then
1031
- if has_enc then
1032
- encoding.sub!(/utf-8-.+$/, 'utf-8') # HACK for stupid emacs formats
1033
- hack_encoding str, encoding
1034
- else
1035
- warn "Skipping magic encoding comment"
1036
- end
1037
- else
1038
- # nothing specified... ugh. try to encode as utf-8
1039
- hack_encoding str if has_enc
1299
+ return [false, false]
1040
1300
  end
1041
-
1042
- str
1043
1301
  end
1044
1302
 
1045
- def hack_encoding str, extra = nil
1046
- encodings = ENCODING_ORDER.dup
1047
- encodings.unshift(extra) unless extra.nil?
1048
-
1049
- # terrible, horrible, no good, very bad, last ditch effort.
1050
- encodings.each do |enc|
1051
- begin
1052
- str.force_encoding enc
1053
- if str.valid_encoding? then
1054
- str.encode! Encoding::UTF_8
1055
- break
1056
- end
1057
- rescue Encoding::InvalidByteSequenceError
1058
- # do nothing
1059
- rescue Encoding::UndefinedConversionError
1060
- # do nothing
1061
- end
1062
- end
1063
-
1064
- # no amount of pain is enough for you.
1065
- raise "Bad encoding. Need a magic encoding comment." unless
1066
- str.encoding.name == "UTF-8"
1303
+ def on_error(et, ev, values)
1304
+ super
1305
+ rescue Racc::ParseError => e
1306
+ # I don't like how the exception obscures the error message
1307
+ e.message.replace "%s:%p :: %s" % [self.file, lexer.lineno, e.message.strip]
1308
+ warn e.message if $DEBUG
1309
+ raise
1067
1310
  end
1068
1311
 
1069
1312
  ##
@@ -1078,7 +1321,7 @@ module RubyParserStuff
1078
1321
 
1079
1322
  self.file = file.dup
1080
1323
 
1081
- @yydebug = ENV.has_key? 'DEBUG'
1324
+ @yydebug = ENV.has_key? "DEBUG"
1082
1325
 
1083
1326
  # HACK -- need to get tests passing more than have graceful code
1084
1327
  self.lexer.ss = RPStringScanner.new str
@@ -1087,40 +1330,29 @@ module RubyParserStuff
1087
1330
  end
1088
1331
  end
1089
1332
 
1090
- alias :parse :process
1333
+ alias parse process
1091
1334
 
1092
1335
  def remove_begin node
1093
- oldnode = node
1094
- if node and node.sexp_type == :begin and node.size == 2 then
1095
- node = node.last
1096
- node.line = oldnode.line
1097
- end
1336
+ line = node.line
1337
+
1338
+ node = node.last while node and node.sexp_type == :begin and node.size == 2
1339
+
1340
+ node = s(:nil) if node == s(:begin)
1341
+
1342
+ node.line ||= line
1343
+
1098
1344
  node
1099
1345
  end
1100
1346
 
1347
+ alias value_expr remove_begin # TODO: for now..? could check the tree, but meh?
1348
+
1101
1349
  def reset
1102
1350
  lexer.reset
1103
1351
  self.in_def = false
1104
1352
  self.in_single = 0
1105
1353
  self.env.reset
1106
1354
  self.comments.clear
1107
- end
1108
-
1109
- def block_dup_check call_or_args, block
1110
- syntax_error "Both block arg and actual block given." if
1111
- block and call_or_args.block_pass?
1112
- end
1113
-
1114
- def inverted? val
1115
- [:return, :next, :break, :yield].include? val[0].sexp_type
1116
- end
1117
-
1118
- def invert_block_call val
1119
- (type, call), iter = val
1120
-
1121
- iter.insert 1, call
1122
-
1123
- [iter, s(type)]
1355
+ self.last_token_type = nil
1124
1356
  end
1125
1357
 
1126
1358
  def ret_args node
@@ -1135,7 +1367,7 @@ module RubyParserStuff
1135
1367
 
1136
1368
  # HACK matz wraps ONE of the FOUR splats in a newline to
1137
1369
  # distinguish. I use paren for now. ugh
1138
- node = s(:svalue, node) if node.sexp_type == :splat and not node.paren
1370
+ node = s(:svalue, node).line node.line if node.sexp_type == :splat and not node.paren
1139
1371
  node.sexp_type = :svalue if node.sexp_type == :arglist && node[1].sexp_type == :splat
1140
1372
  end
1141
1373
 
@@ -1144,18 +1376,17 @@ module RubyParserStuff
1144
1376
 
1145
1377
  def s(*args)
1146
1378
  result = Sexp.new(*args)
1147
- result.line ||= lexer.lineno if lexer.ss # otherwise...
1379
+ # result.line ||= lexer.lineno if lexer.ss unless ENV["CHECK_LINE_NUMS"] # otherwise...
1148
1380
  result.file = self.file
1149
1381
  result
1150
1382
  end
1151
1383
 
1152
- def value_expr oldnode # HACK: much more to do
1153
- node = remove_begin oldnode
1154
- node.line = oldnode.line if oldnode
1155
- node[2] = value_expr node[2] if node and node.sexp_type == :if
1156
- node
1384
+ def syntax_error msg
1385
+ raise RubyParser::SyntaxError, msg
1157
1386
  end
1158
1387
 
1388
+ alias yyerror syntax_error
1389
+
1159
1390
  def void_stmts node
1160
1391
  return nil unless node
1161
1392
  return node unless node.sexp_type == :block
@@ -1173,17 +1404,34 @@ module RubyParserStuff
1173
1404
  # do nothing for now
1174
1405
  end
1175
1406
 
1176
- alias yyerror syntax_error
1407
+ def whitespace_width line, remove_width = nil
1408
+ col = 0
1409
+ idx = 0
1177
1410
 
1178
- def on_error(et, ev, values)
1179
- super
1180
- rescue Racc::ParseError => e
1181
- # I don't like how the exception obscures the error message
1182
- e.message.replace "%s:%p :: %s" % [self.file, lexer.lineno, e.message.strip]
1183
- warn e.message if $DEBUG
1184
- raise
1411
+ line.chars.each do |c|
1412
+ break if remove_width && col >= remove_width
1413
+ case c
1414
+ when " " then
1415
+ col += 1
1416
+ when "\t" then
1417
+ n = TAB_WIDTH * (col / TAB_WIDTH + 1)
1418
+ break if remove_width && n > remove_width
1419
+ col = n
1420
+ else
1421
+ break
1422
+ end
1423
+ idx += 1
1424
+ end
1425
+
1426
+ if remove_width then
1427
+ line[idx..-1]
1428
+ else
1429
+ col
1430
+ end
1185
1431
  end
1186
1432
 
1433
+ alias remove_whitespace_width whitespace_width
1434
+
1187
1435
  class Keyword
1188
1436
  include RubyLexer::State::Values
1189
1437
 
@@ -1214,8 +1462,10 @@ module RubyParserStuff
1214
1462
  # :expr_fitem = symbol literal as FNAME.
1215
1463
  # :expr_value = :expr_beg -- work to remove. Need multi-state support.
1216
1464
 
1465
+ expr_woot = EXPR_FNAME|EXPR_FITEM
1466
+
1217
1467
  wordlist = [
1218
- ["alias", [:kALIAS, :kALIAS ], EXPR_FNAME|EXPR_FITEM],
1468
+ ["alias", [:kALIAS, :kALIAS ], expr_woot ],
1219
1469
  ["and", [:kAND, :kAND ], EXPR_BEG ],
1220
1470
  ["begin", [:kBEGIN, :kBEGIN ], EXPR_BEG ],
1221
1471
  ["break", [:kBREAK, :kBREAK ], EXPR_MID ],
@@ -1245,7 +1495,7 @@ module RubyParserStuff
1245
1495
  ["super", [:kSUPER, :kSUPER ], EXPR_ARG ],
1246
1496
  ["then", [:kTHEN, :kTHEN ], EXPR_BEG ],
1247
1497
  ["true", [:kTRUE, :kTRUE ], EXPR_END ],
1248
- ["undef", [:kUNDEF, :kUNDEF ], EXPR_FNAME|EXPR_FITEM],
1498
+ ["undef", [:kUNDEF, :kUNDEF ], expr_woot ],
1249
1499
  ["unless", [:kUNLESS, :kUNLESS_MOD ], EXPR_BEG ],
1250
1500
  ["until", [:kUNTIL, :kUNTIL_MOD ], EXPR_BEG ],
1251
1501
  ["when", [:kWHEN, :kWHEN ], EXPR_BEG ],
@@ -1325,11 +1575,6 @@ module RubyParserStuff
1325
1575
  @debug = debug
1326
1576
  end
1327
1577
 
1328
- def reset
1329
- @stack = [false]
1330
- log :reset if debug
1331
- end
1332
-
1333
1578
  def inspect
1334
1579
  "StackState(#{@name}, #{@stack.inspect})"
1335
1580
  end
@@ -1366,16 +1611,21 @@ module RubyParserStuff
1366
1611
  log :push if debug
1367
1612
  end
1368
1613
 
1369
- def store base = false
1370
- result = @stack.dup
1371
- @stack.replace [base]
1372
- log :store if debug
1373
- result
1614
+ def reset
1615
+ @stack = [false]
1616
+ log :reset if debug
1374
1617
  end
1375
1618
 
1376
1619
  def restore oldstate
1377
1620
  @stack.replace oldstate
1378
1621
  log :restore if debug
1379
1622
  end
1623
+
1624
+ def store base = false
1625
+ result = @stack.dup
1626
+ @stack.replace [base]
1627
+ log :store if debug
1628
+ result
1629
+ end
1380
1630
  end
1381
1631
  end