Source

par / lib / par / source.rb

module Par
  # Source consumes a string bit by bit. It defines methods to consume a string
  # conditionally or unconditionally, never touching the original string, 
  # instead slicing it up into small results. 
  #
  # String access methods are relative to the current position, unless mentioned
  # otherwise: 
  # * #string reads a given string
  # * #patterm matches a pattern
  # * #n reads n characters
  class Source
    attr_reader :str 
    attr_reader :pos

    def initialize str
      @str = str
      @pos = 0
    end

    def string str
      if head(str.size) == str
        return self.n(str.size)
      end

      Par.bottom
    end
    def pattern pat
      idx = head.index(pat)
      return bottom unless idx == 0
      md =head.match(pat)
      n(md[0].size)
    end

    def n n
      Par.result(head(n)).tap { @pos += n }
    end

    def conditional_rewind
      old_pos = @pos
      r = yield
      old_pos = @pos if r != Par.bottom

      return r
    ensure
      @pos = old_pos
    end
    alias :cr :conditional_rewind

    def either &block
      Lazy.new self, &block
    end

    def head n=nil
      n && str[@pos, n] || str[@pos..-1]
    end
  end
end