antlr3 1.6.0 → 1.6.3
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.
- data/History.txt +8 -0
- data/Manifest.txt +94 -0
- data/README.txt +1 -1
- data/Rakefile +58 -0
- data/bin/antlr4ruby +101 -7
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +38 -10
- data/lib/antlr3/constants.rb +13 -5
- data/lib/antlr3/debug.rb +57 -57
- data/lib/antlr3/dfa.rb +138 -68
- data/lib/antlr3/dot.rb +32 -32
- data/lib/antlr3/error.rb +85 -78
- data/lib/antlr3/main.rb +191 -187
- data/lib/antlr3/profile.rb +71 -70
- data/lib/antlr3/recognizers.rb +261 -226
- data/lib/antlr3/streams.rb +85 -84
- data/lib/antlr3/streams/interactive.rb +20 -27
- data/lib/antlr3/streams/rewrite.rb +89 -89
- data/lib/antlr3/task.rb +42 -33
- data/lib/antlr3/template.rb +2 -2
- data/lib/antlr3/template/group-lexer.rb +1 -1
- data/lib/antlr3/token.rb +76 -68
- data/lib/antlr3/tree.rb +125 -121
- data/lib/antlr3/tree/visitor.rb +1 -1
- data/lib/antlr3/tree/wizard.rb +1 -1
- data/lib/antlr3/util.rb +32 -33
- data/lib/antlr3/version.rb +3 -3
- data/templates/Ruby.stg +1 -1
- data/test/unit/test-streams.rb +11 -10
- data/test/unit/test-template.rb +206 -204
- metadata +4 -2
data/lib/antlr3/streams.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
=begin LICENSE
|
5
5
|
|
6
6
|
[The "BSD licence"]
|
7
|
-
Copyright (c) 2009 Kyle Yetter
|
7
|
+
Copyright (c) 2009-2010 Kyle Yetter
|
8
8
|
All rights reserved.
|
9
9
|
|
10
10
|
Redistribution and use in source and binary forms, with or without
|
@@ -251,7 +251,8 @@ to keep it simple and familliar in this Ruby runtime API.
|
|
251
251
|
module CharacterStream
|
252
252
|
include Stream
|
253
253
|
extend ClassMacros
|
254
|
-
|
254
|
+
include Constants
|
255
|
+
#EOF = -1
|
255
256
|
|
256
257
|
##
|
257
258
|
# :method: substring(start,stop)
|
@@ -384,16 +385,16 @@ class StringStream
|
|
384
385
|
# [:line] the initial line number; default: +1+
|
385
386
|
# [:column] the initial column number; default: +0+
|
386
387
|
#
|
387
|
-
def initialize(data, options = {})
|
388
|
+
def initialize( data, options = {} )
|
388
389
|
@data = data.to_s
|
389
|
-
@data.equal?(data) and @data = @data.clone
|
390
|
+
@data.equal?( data ) and @data = @data.clone
|
390
391
|
@data.freeze
|
391
392
|
@position = 0
|
392
393
|
@line = options.fetch :line, 1
|
393
394
|
@column = options.fetch :column, 0
|
394
395
|
@markers = []
|
395
396
|
mark
|
396
|
-
@name ||= options[:file] || options[:name] # || '(string)'
|
397
|
+
@name ||= options[ :file ] || options[ :name ] # || '(string)'
|
397
398
|
end
|
398
399
|
|
399
400
|
def size
|
@@ -417,7 +418,7 @@ class StringStream
|
|
417
418
|
# advance the stream by one character; returns the character consumed
|
418
419
|
#
|
419
420
|
def consume
|
420
|
-
c = @data[@position] || EOF
|
421
|
+
c = @data[ @position ] || EOF
|
421
422
|
if @position < @data.length
|
422
423
|
@column += 1
|
423
424
|
if c == ?\n
|
@@ -426,7 +427,7 @@ class StringStream
|
|
426
427
|
end
|
427
428
|
@position += 1
|
428
429
|
end
|
429
|
-
return(c)
|
430
|
+
return( c )
|
430
431
|
end
|
431
432
|
|
432
433
|
#
|
@@ -435,25 +436,25 @@ class StringStream
|
|
435
436
|
# value of +k+ returns previous characters consumed, where <tt>k = -1</tt> is the last
|
436
437
|
# character consumed. <tt>k = 0</tt> has undefined behavior and returns +nil+
|
437
438
|
#
|
438
|
-
def peek(k = 1)
|
439
|
+
def peek( k = 1 )
|
439
440
|
k == 0 and return nil
|
440
441
|
k += 1 if k < 0
|
441
442
|
index = @position + k - 1
|
442
443
|
index < 0 and return nil
|
443
|
-
@data[index] or EOF
|
444
|
+
@data[ index ] or EOF
|
444
445
|
end
|
445
446
|
|
446
447
|
#
|
447
448
|
# identical to #peek, except it returns the character value as a String
|
448
449
|
#
|
449
|
-
def look(k = 1)
|
450
|
+
def look( k = 1 )
|
450
451
|
k == 0 and return nil
|
451
452
|
k += 1 if k < 0
|
452
453
|
|
453
454
|
index = @position + k - 1
|
454
455
|
index < 0 and return nil
|
455
456
|
|
456
|
-
c = @data[index] and c.chr
|
457
|
+
c = @data[ index ] and c.chr
|
457
458
|
end
|
458
459
|
|
459
460
|
#
|
@@ -461,9 +462,9 @@ class StringStream
|
|
461
462
|
# if <tt>k >= 0</tt>, return the next k characters
|
462
463
|
# if <tt>k < 0</tt>, return the previous <tt>|k|</tt> characters
|
463
464
|
#
|
464
|
-
def through(k)
|
465
|
+
def through( k )
|
465
466
|
if k >= 0 then @data[ @position, k ] else
|
466
|
-
start = (@position + k).at_least( 0 ) # start cannot be negative or index will wrap around
|
467
|
+
start = ( @position + k ).at_least( 0 ) # start cannot be negative or index will wrap around
|
467
468
|
@data[ start ... @position ]
|
468
469
|
end
|
469
470
|
end
|
@@ -472,7 +473,7 @@ class StringStream
|
|
472
473
|
alias >> look
|
473
474
|
|
474
475
|
# operator style look-behind
|
475
|
-
def <<(k)
|
476
|
+
def <<( k )
|
476
477
|
self << -k
|
477
478
|
end
|
478
479
|
|
@@ -486,7 +487,7 @@ class StringStream
|
|
486
487
|
# This is an extra utility method for use inside lexer actions if needed.
|
487
488
|
#
|
488
489
|
def beginning_of_line?
|
489
|
-
@position.zero? or @data[@position - 1] == ?\n
|
490
|
+
@position.zero? or @data[ @position - 1 ] == ?\n
|
490
491
|
end
|
491
492
|
|
492
493
|
#
|
@@ -494,7 +495,7 @@ class StringStream
|
|
494
495
|
# This is an extra utility method for use inside lexer actions if needed.
|
495
496
|
#
|
496
497
|
def end_of_line?
|
497
|
-
@data[@position] == ?\n if @position >= @data.length
|
498
|
+
@data[ @position ] == ?\n if @position >= @data.length
|
498
499
|
end
|
499
500
|
|
500
501
|
#
|
@@ -522,7 +523,7 @@ class StringStream
|
|
522
523
|
# position with the #rewind method. This method is used to implement backtracking.
|
523
524
|
#
|
524
525
|
def mark
|
525
|
-
state = [@position, @line, @column].freeze
|
526
|
+
state = [ @position, @line, @column ].freeze
|
526
527
|
@markers << state
|
527
528
|
return @markers.length - 1
|
528
529
|
end
|
@@ -531,10 +532,10 @@ class StringStream
|
|
531
532
|
# restore the stream to an earlier location recorded by #mark. If no marker value is
|
532
533
|
# provided, the last marker generated by #mark will be used.
|
533
534
|
#
|
534
|
-
def rewind(marker = @markers.length - 1, release = true)
|
535
|
-
(marker >= 0 and location = @markers[marker]) or return(self)
|
535
|
+
def rewind( marker = @markers.length - 1, release = true )
|
536
|
+
( marker >= 0 and location = @markers[ marker ] ) or return( self )
|
536
537
|
@position, @line, @column = location
|
537
|
-
release(marker) if release
|
538
|
+
release( marker ) if release
|
538
539
|
return self
|
539
540
|
end
|
540
541
|
|
@@ -556,9 +557,9 @@ class StringStream
|
|
556
557
|
# let go of the bookmark data for the marker and all marker
|
557
558
|
# values created after the marker.
|
558
559
|
#
|
559
|
-
def release(marker = @markers.length - 1)
|
560
|
-
marker.between?(1, @markers.length - 1) or return
|
561
|
-
@markers
|
560
|
+
def release( marker = @markers.length - 1 )
|
561
|
+
marker.between?( 1, @markers.length - 1 ) or return
|
562
|
+
@markers.pop( @markers.length - marker )
|
562
563
|
return self
|
563
564
|
end
|
564
565
|
|
@@ -567,15 +568,15 @@ class StringStream
|
|
567
568
|
# note: if +index+ is before the current position, the +line+ and +column+
|
568
569
|
# attributes of the stream will probably be incorrect
|
569
570
|
#
|
570
|
-
def seek(index)
|
571
|
+
def seek( index )
|
571
572
|
index = index.bound( 0, @data.length ) # ensures index is within the stream's range
|
572
573
|
if index > @position
|
573
574
|
skipped = through( index - @position )
|
574
|
-
if lc = skipped.count("\n") and lc.zero?
|
575
|
+
if lc = skipped.count( "\n" ) and lc.zero?
|
575
576
|
@column += skipped.length
|
576
577
|
else
|
577
578
|
@line += lc
|
578
|
-
@column = skipped.length - skipped.rindex("\n") - 1
|
579
|
+
@column = skipped.length - skipped.rindex( "\n" ) - 1
|
579
580
|
end
|
580
581
|
end
|
581
582
|
@position = index
|
@@ -589,29 +590,29 @@ class StringStream
|
|
589
590
|
# * +before_chars+ characters before the cursor (6 characters by default)
|
590
591
|
# * +after_chars+ characters after the cursor (10 characters by default)
|
591
592
|
#
|
592
|
-
def inspect(before_chars = 6, after_chars = 10)
|
593
|
+
def inspect( before_chars = 6, after_chars = 10 )
|
593
594
|
before = through( -before_chars ).inspect
|
594
|
-
@position - before_chars > 0 and before.insert(0, '... ')
|
595
|
+
@position - before_chars > 0 and before.insert( 0, '... ' )
|
595
596
|
|
596
597
|
after = through( after_chars ).inspect
|
597
598
|
@position + after_chars + 1 < @data.length and after << ' ...'
|
598
599
|
|
599
600
|
location = "#@position / line #@line:#@column"
|
600
|
-
"#<#{self.class}: #{before} | #{after} @ #{location}>"
|
601
|
+
"#<#{ self.class }: #{ before } | #{ after } @ #{ location }>"
|
601
602
|
end
|
602
603
|
|
603
604
|
#
|
604
605
|
# return the string slice between position +start+ and +stop+
|
605
606
|
#
|
606
|
-
def substring(start, stop)
|
607
|
-
@data[start, stop - start + 1]
|
607
|
+
def substring( start, stop )
|
608
|
+
@data[ start, stop - start + 1 ]
|
608
609
|
end
|
609
610
|
|
610
611
|
#
|
611
612
|
# identical to String#[]
|
612
613
|
#
|
613
|
-
def [](start, *args)
|
614
|
-
@data[start, *args]
|
614
|
+
def []( start, *args )
|
615
|
+
@data[ start, *args ]
|
615
616
|
end
|
616
617
|
end
|
617
618
|
|
@@ -640,31 +641,31 @@ class FileStream < StringStream
|
|
640
641
|
# see StringStream.new for a list of additional options
|
641
642
|
# the constructer accepts
|
642
643
|
#
|
643
|
-
def initialize(file, options = {})
|
644
|
+
def initialize( file, options = {} )
|
644
645
|
case file
|
645
646
|
when $stdin then
|
646
647
|
data = $stdin.read
|
647
648
|
@name = '(stdin)'
|
648
649
|
when ::File then
|
649
650
|
file = file.clone
|
650
|
-
file.reopen(file.path, 'r')
|
651
|
+
file.reopen( file.path, 'r' )
|
651
652
|
@name = file.path
|
652
653
|
data = file.read
|
653
654
|
file.close
|
654
655
|
else
|
655
|
-
if file.respond_to?(:read)
|
656
|
+
if file.respond_to?( :read )
|
656
657
|
data = file.read
|
657
|
-
if file.respond_to?(:name) then @name = file.name
|
658
|
-
elsif file.respond_to?(:path) then @name = file.path
|
658
|
+
if file.respond_to?( :name ) then @name = file.name
|
659
|
+
elsif file.respond_to?( :path ) then @name = file.path
|
659
660
|
end
|
660
661
|
else
|
661
662
|
@name = file.to_s
|
662
|
-
if test(?f, @name) then data = File.read(@name)
|
663
|
+
if test( ?f, @name ) then data = File.read( @name )
|
663
664
|
else raise ArgumentError, "could not find an existing file at %p" % @name
|
664
665
|
end
|
665
666
|
end
|
666
667
|
end
|
667
|
-
super(data, options)
|
668
|
+
super( data, options )
|
668
669
|
end
|
669
670
|
|
670
671
|
end
|
@@ -749,7 +750,7 @@ class CommonTokenStream
|
|
749
750
|
@tokens.each_with_index { |t, i| t.index = i }
|
750
751
|
@position =
|
751
752
|
if first_token = @tokens.find { |t| t.channel == @channel }
|
752
|
-
@tokens.index(first_token)
|
753
|
+
@tokens.index( first_token )
|
753
754
|
else @tokens.length
|
754
755
|
end
|
755
756
|
end
|
@@ -762,18 +763,18 @@ class CommonTokenStream
|
|
762
763
|
# behavior to CommonTokenStream.new, if a block is provided, tokens will be
|
763
764
|
# yielded and discarded if the block returns a +false+ or +nil+ value.
|
764
765
|
#
|
765
|
-
def rebuild(token_source = nil)
|
766
|
+
def rebuild( token_source = nil )
|
766
767
|
if token_source.nil?
|
767
768
|
@token_source.reset rescue nil
|
768
769
|
else @token_source = token_source
|
769
770
|
end
|
770
|
-
@tokens = block_given? ? @token_source.select { |token| yield(token) } :
|
771
|
+
@tokens = block_given? ? @token_source.select { |token| yield( token ) } :
|
771
772
|
@token_source.to_a
|
772
773
|
@tokens.each_with_index { |t, i| t.index = i }
|
773
774
|
@last_marker = nil
|
774
775
|
@position =
|
775
776
|
if first_token = @tokens.find { |t| t.channel == @channel }
|
776
|
-
@tokens.index(first_token)
|
777
|
+
@tokens.index( first_token )
|
777
778
|
else @tokens.length
|
778
779
|
end
|
779
780
|
return self
|
@@ -782,7 +783,7 @@ class CommonTokenStream
|
|
782
783
|
#
|
783
784
|
# tune the stream to a new channel value
|
784
785
|
#
|
785
|
-
def tune_to(channel)
|
786
|
+
def tune_to( channel )
|
786
787
|
@channel = channel
|
787
788
|
end
|
788
789
|
|
@@ -808,7 +809,7 @@ class CommonTokenStream
|
|
808
809
|
#
|
809
810
|
def reset
|
810
811
|
@position = 0
|
811
|
-
@position += 1 while token = @tokens[@position] and
|
812
|
+
@position += 1 while token = @tokens[ @position ] and
|
812
813
|
token.channel != @channel
|
813
814
|
@last_marker = nil
|
814
815
|
return self
|
@@ -821,13 +822,13 @@ class CommonTokenStream
|
|
821
822
|
@last_marker = @position
|
822
823
|
end
|
823
824
|
|
824
|
-
def release(marker = nil)
|
825
|
+
def release( marker = nil )
|
825
826
|
# do nothing
|
826
827
|
end
|
827
828
|
|
828
829
|
|
829
|
-
def rewind(marker = @last_marker, release = true)
|
830
|
-
seek(marker)
|
830
|
+
def rewind( marker = @last_marker, release = true )
|
831
|
+
seek( marker )
|
831
832
|
end
|
832
833
|
|
833
834
|
|
@@ -837,11 +838,11 @@ class CommonTokenStream
|
|
837
838
|
# advance the stream one step to the next on-channel token
|
838
839
|
#
|
839
840
|
def consume
|
840
|
-
token = @tokens[@position] || EOF_TOKEN
|
841
|
+
token = @tokens[ @position ] || EOF_TOKEN
|
841
842
|
if @position < @tokens.length
|
842
|
-
@position = future?(2) || @tokens.length
|
843
|
+
@position = future?( 2 ) || @tokens.length
|
843
844
|
end
|
844
|
-
return(token)
|
845
|
+
return( token )
|
845
846
|
end
|
846
847
|
|
847
848
|
#
|
@@ -849,8 +850,8 @@ class CommonTokenStream
|
|
849
850
|
# note: seek does not check whether or not the
|
850
851
|
# token at the specified position is on-channel,
|
851
852
|
#
|
852
|
-
def seek(index)
|
853
|
-
@position = index.to_i.bound(0, @tokens.length)
|
853
|
+
def seek( index )
|
854
|
+
@position = index.to_i.bound( 0, @tokens.length )
|
854
855
|
return self
|
855
856
|
end
|
856
857
|
|
@@ -860,16 +861,16 @@ class CommonTokenStream
|
|
860
861
|
# value of +k+ returns previous on-channel tokens consumed, where <tt>k = -1</tt> is the last
|
861
862
|
# on-channel token consumed. <tt>k = 0</tt> has undefined behavior and returns +nil+
|
862
863
|
#
|
863
|
-
def peek(k = 1)
|
864
|
-
tk = look(k) and return(tk.type)
|
864
|
+
def peek( k = 1 )
|
865
|
+
tk = look( k ) and return( tk.type )
|
865
866
|
end
|
866
867
|
|
867
868
|
#
|
868
869
|
# operates simillarly to #peek, but returns the full token object at look-ahead position +k+
|
869
870
|
#
|
870
|
-
def look(k = 1)
|
871
|
-
index = future?(k) or return nil
|
872
|
-
@tokens.fetch(index, EOF_TOKEN)
|
871
|
+
def look( k = 1 )
|
872
|
+
index = future?( k ) or return nil
|
873
|
+
@tokens.fetch( index, EOF_TOKEN )
|
873
874
|
end
|
874
875
|
|
875
876
|
alias >> look
|
@@ -881,21 +882,21 @@ class CommonTokenStream
|
|
881
882
|
# returns the index of the on-channel token at look-ahead position +k+ or nil if no other
|
882
883
|
# on-channel tokens exist
|
883
884
|
#
|
884
|
-
def future?(k = 1)
|
885
|
+
def future?( k = 1 )
|
885
886
|
@position == -1 and fill_buffer
|
886
887
|
|
887
888
|
case
|
888
889
|
when k == 0 then nil
|
889
|
-
when k < 0 then past?(-k)
|
890
|
+
when k < 0 then past?( -k )
|
890
891
|
when k == 1 then @position
|
891
892
|
else
|
892
893
|
# since the stream only yields on-channel
|
893
894
|
# tokens, the stream can't just go to the
|
894
895
|
# next position, but rather must skip
|
895
896
|
# over off-channel tokens
|
896
|
-
(k - 1).times.inject(@position) do |cursor, |
|
897
|
+
( k - 1 ).times.inject( @position ) do |cursor, |
|
897
898
|
begin
|
898
|
-
tk = @tokens.at(cursor += 1) or return(cursor)
|
899
|
+
tk = @tokens.at( cursor += 1 ) or return( cursor )
|
899
900
|
# ^- if tk is nil (i.e. i is outside array limits)
|
900
901
|
end until tk.channel == @channel
|
901
902
|
cursor
|
@@ -907,7 +908,7 @@ class CommonTokenStream
|
|
907
908
|
# returns the index of the on-channel token at look-behind position +k+ or nil if no other
|
908
909
|
# on-channel tokens exist before the current token
|
909
910
|
#
|
910
|
-
def past?(k = 1)
|
911
|
+
def past?( k = 1 )
|
911
912
|
@position == -1 and fill_buffer
|
912
913
|
|
913
914
|
case
|
@@ -915,10 +916,10 @@ class CommonTokenStream
|
|
915
916
|
when @position - k < 0 then nil
|
916
917
|
else
|
917
918
|
|
918
|
-
k.times.inject(@position) do |cursor, |
|
919
|
+
k.times.inject( @position ) do |cursor, |
|
919
920
|
begin
|
920
|
-
cursor <= 0 and return(nil)
|
921
|
-
tk = @tokens.at(cursor -= 1) or return(nil)
|
921
|
+
cursor <= 0 and return( nil )
|
922
|
+
tk = @tokens.at( cursor -= 1 ) or return( nil )
|
922
923
|
end until tk.channel == @channel
|
923
924
|
cursor
|
924
925
|
end
|
@@ -931,9 +932,9 @@ class CommonTokenStream
|
|
931
932
|
# If no block is provided, the method returns an Enumerator object.
|
932
933
|
# #each accepts the same arguments as #tokens
|
933
934
|
#
|
934
|
-
def each(*args)
|
935
|
-
block_given? or return enum_for(:each, *args)
|
936
|
-
tokens(*args).each { |token| yield(token) }
|
935
|
+
def each( *args )
|
936
|
+
block_given? or return enum_for( :each, *args )
|
937
|
+
tokens( *args ).each { |token| yield( token ) }
|
937
938
|
end
|
938
939
|
|
939
940
|
#
|
@@ -944,36 +945,36 @@ class CommonTokenStream
|
|
944
945
|
# yielded and filtered out of the return array if the block returns a +false+
|
945
946
|
# or +nil+ value.
|
946
947
|
#
|
947
|
-
def tokens(start = nil, stop = nil)
|
948
|
+
def tokens( start = nil, stop = nil )
|
948
949
|
stop.nil? || stop >= @tokens.length and stop = @tokens.length - 1
|
949
950
|
start.nil? || stop < 0 and start = 0
|
950
|
-
tokens = @tokens[start..stop]
|
951
|
+
tokens = @tokens[ start..stop ]
|
951
952
|
|
952
953
|
if block_given?
|
953
|
-
tokens.delete_if { |t| not yield(t) }
|
954
|
+
tokens.delete_if { |t| not yield( t ) }
|
954
955
|
end
|
955
956
|
|
956
957
|
return( tokens )
|
957
958
|
end
|
958
959
|
|
959
960
|
|
960
|
-
def at(i)
|
961
|
+
def at( i )
|
961
962
|
@tokens.at i
|
962
963
|
end
|
963
964
|
|
964
965
|
#
|
965
966
|
# identical to Array#[], as applied to the stream's token buffer
|
966
967
|
#
|
967
|
-
def [](i, *args)
|
968
|
-
@tokens[i, *args]
|
968
|
+
def []( i, *args )
|
969
|
+
@tokens[ i, *args ]
|
969
970
|
end
|
970
971
|
|
971
972
|
###### Standard Conversion Methods ###############################
|
972
973
|
def inspect
|
973
974
|
string = "#<%p: @token_source=%p @ %p/%p" %
|
974
|
-
[self.class, @token_source.class, @position, @tokens.length]
|
975
|
-
tk = look(-1) and string << " #{tk.inspect} <--"
|
976
|
-
tk = look( 1) and string << " --> #{tk.inspect}"
|
975
|
+
[ self.class, @token_source.class, @position, @tokens.length ]
|
976
|
+
tk = look( -1 ) and string << " #{ tk.inspect } <--"
|
977
|
+
tk = look( 1 ) and string << " --> #{ tk.inspect }"
|
977
978
|
string << '>'
|
978
979
|
end
|
979
980
|
|
@@ -981,14 +982,14 @@ class CommonTokenStream
|
|
981
982
|
# fetches the text content of all tokens between +start+ and +stop+ and
|
982
983
|
# joins the chunks into a single string
|
983
984
|
#
|
984
|
-
def extract_text(start = 0, stop = @tokens.length - 1)
|
985
|
-
start = start.to_i.at_least(0)
|
986
|
-
stop = stop.to_i.at_most(@tokens.length)
|
987
|
-
@tokens[start..stop].map! { |t| t.text }.join('')
|
985
|
+
def extract_text( start = 0, stop = @tokens.length - 1 )
|
986
|
+
start = start.to_i.at_least( 0 )
|
987
|
+
stop = stop.to_i.at_most( @tokens.length )
|
988
|
+
@tokens[ start..stop ].map! { |t| t.text }.join( '' )
|
988
989
|
end
|
989
990
|
|
990
991
|
alias to_s extract_text
|
991
992
|
|
992
993
|
end
|
993
994
|
|
994
|
-
end
|
995
|
+
end
|