ddfreyne/d-parse

View on GitHub
lib/d-parse/parsers/combinators/repeat.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module DParse
  module Parsers
    class Repeat < DParse::Parser
      def initialize(parser)
        @parser = parser
      end

      def read(input, pos)
        prev_res = Success.new(input, pos, data: [])
        best_failure = nil

        loop do
          new_res = @parser.read(input, prev_res.pos)
          best_failure = find_best_failure(best_failure, new_res)

          return prev_res.with_best_failure(best_failure) if prev_res.pos.index == new_res.pos.index

          case new_res
          when Success
            prev_res = new_res.map { |d| prev_res.data + [d] }
          else
            return prev_res.with_best_failure(best_failure)
          end
        end
      end

      def inspect
        "repeat(#{@parser})"
      end

      private

      def find_best_failure(*results)
        results
          .select { |r| r.is_a?(DParse::Failure) }
          .max_by { |r| r.pos.index }
      end
    end
  end
end