#
# rscan.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program
# under the same terms of ruby.
#

class StringScanner_R

  Id_R = "$Id: rscan.rb,v 1.13 2003/03/25 02:04:21 aamine Exp $"
  Version_R = '0.6.7'
  Revision_R = %q$Revision: 1.13 $.split[1]

  def self.must_C_version
    raise NotImplementedError, 'strscan is not C version'
  end

  def initialize( str, dup = true )
    @rest = @str = dup ? str.dup : str
    @str.freeze
    @prev = nil
    @last_match = nil
  end

  attr_reader :last_match

  def inspect
    ret = "#<#{self.class} #{@str.size - @rest.size}/#{@str.size} "
    pos = @str.size - @rest.size
    if pos > 0 then
      ret << ' '
      beg = pos - 5
      beg = 0 if beg < 0
      ret << '"...' if beg > 0
      ret << @str[beg..pos].inspect[1..-1]
    end
    ret << ' @'
    unless @rest.empty? then
      ret << ' ' << @rest[0,5].inspect
      ret[-1,1] = '..."' if @rest.size > 5
    end
    ret << '>'

    ret
  end

  def scan( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest = m.post_match
      m[0]
    else
      @last_match = @prev = nil
      nil
    end
  end

  def skip( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest = m.post_match
      @prev.size - @rest.size
    else
      @prev = nil
      @last_match = nil
      nil
    end
  end

  def match?( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      m.end(0)
    else
      @prev = nil
      @last_match = nil
      nil
    end
  end

  def check( re )
    if m = re.match( @rest ) then
      @last_match = m
      @prev = @rest
      @rest[ 0, m.end(0) ]
    else
      @prev = @last_match = nil
      nil
    end
  end

  def scan_until( re )
    if skip re then
      @last_match.pre_match + @last_match[0]
    else
      nil
    end
  end

  alias skip_until skip
  alias exist? match?
  alias check_until check

  def getch
    scan( /./ )
  end

  def eos?
    @rest.empty?
  end

  alias empty? eos?

  def rest?
    not @rest.empty?
  end

  def rest
    @rest.dup
  end

  def restsize
    @rest.size
  end

  def matched?
    not @last_match.nil?
  end

  def matched
    @last_match[0]
  end

  def matchedsize
    m = @last_match
    m.end(0) - m.begin(0)
  end

  def [](n)
    @last_match[n]
  end

  def string
    @str
  end

  def string=( s )
    @str = @rest = s
    @prev = nil
  end

  def pos
    @str.size - @rest.size
  end

  def pos=( i )
    @rest = @str[ i, @str.size - i ]
  end

  alias pointer  pos
  alias pointer= pos=

  def reset
    @rest = @str
    @prev = @last_match = nil
  end

  def clear
    @rest = ''
    @prev = @last_match = nil
  end

  def unscan
    @prev or raise ScanError, 'cannot unscan: not scanned yet'
    @rest = @prev
    @prev = nil
  end

end   # class StringScanner_R
