Home | History | Annotate | Download | only in streams
      1 #!/usr/bin/ruby
      2 # encoding: utf-8
      3 
      4 module ANTLR3
      5 
      6 =begin rdoc ANTLR3::Main::InteractiveStringStream
      7 
      8 A special stream used in the <b>interactive mode</b> of the Main scripts. It
      9 uses Readline (if available) or standard IO#gets to fetch data on demand.
     10 
     11 =end
     12 
     13 class InteractiveStringStream < StringStream
     14   
     15   if RUBY_VERSION =~ /^1\.9/
     16     
     17     # creates a new StringStream object where +data+ is the string data to stream.
     18     # accepts the following options in a symbol-to-value hash:
     19     #
     20     # [:file or :name] the (file) name to associate with the stream; default: <tt>'(string)'</tt>
     21     # [:line] the initial line number; default: +1+
     22     # [:column] the initial column number; default: +0+
     23     # 
     24     def initialize( options = {}, &block )      # for 1.9
     25       @string = ''
     26       @data   = []
     27       @position = options.fetch :position, 0
     28       @line     = options.fetch :line, 1
     29       @column   = options.fetch :column, 0
     30       @markers  = []
     31       mark
     32       @initialized = @eof = false
     33       @readline = block or raise( ArgumentError, "no line-reading block was provided" )
     34       @name ||= options[ :file ] || options[ :name ] || '(interactive)'
     35     end
     36     
     37     def readline
     38       @initialized = true
     39       unless @eof
     40         if line = @readline.call
     41           line = line.to_s.encode( Encoding::UTF_8 )
     42           @string << line
     43           @data.concat( line.codepoints.to_a )
     44           return true
     45         else
     46           @eof = true
     47           return false
     48         end
     49       end
     50     end
     51     
     52   else
     53     
     54     # creates a new StringStream object where +data+ is the string data to stream.
     55     # accepts the following options in a symbol-to-value hash:
     56     #
     57     # [:file or :name] the (file) name to associate with the stream; default: <tt>'(string)'</tt>
     58     # [:line] the initial line number; default: +1+
     59     # [:column] the initial column number; default: +0+
     60     # 
     61     def initialize( options = {}, &block )
     62       @string = @data = ''
     63       @position = options.fetch :position, 0
     64       @line     = options.fetch :line, 1
     65       @column   = options.fetch :column, 0
     66       @markers = []
     67       mark
     68       @initialized = @eof = false
     69       @readline = block or raise( ArgumentError, "no line-reading block was provided" )
     70       @name ||= options[ :file ] || options[ :name ] || '(interactive)'
     71     end
     72     
     73     def readline
     74       @initialized = true
     75       unless @eof
     76         if line = @readline.call
     77           @data << line.to_s
     78           return true
     79         else
     80           @eof = true
     81           return false
     82         end
     83       end
     84     end
     85     
     86   end
     87   
     88   private :readline
     89   
     90   def consume
     91     @position < @data.size and return( super )
     92     unless @eof
     93       readline
     94       consume
     95     end
     96   end
     97   
     98   def peek( i = 1 )
     99     i.zero? and return 0
    100     i += 1 if i < 0
    101     index = @position + i - 1
    102     index < 0 and return 0
    103     
    104     if index < @data.size
    105       char = @data[ index ]
    106     elsif readline
    107       peek( i )
    108     else EOF
    109     end
    110   end
    111   
    112   def look( i = 1 )
    113     peek( i ).chr rescue EOF
    114   end
    115   
    116   def substring( start, stop )
    117     fill_through( stop )
    118     @string[ start .. stop ]
    119   end
    120   
    121 private
    122   
    123   def fill_through( position )
    124     @eof and return
    125     if @position < 0 then fill_out
    126     else readline until ( @data.size > @position or @eof )
    127     end
    128   end
    129   
    130   def fill_out
    131     @eof and return
    132     readline until @eof
    133   end
    134 end
    135 
    136 end
    137