class RuboCop::NodePattern::Compiler::Sequence

(head *first_terms variadic_term *last_terms)
Builds Ruby code for a sequence
@private

def compile

def compile
  [
    compile_guard_clause,
    compile_child_nb_guard,
    compile_seq_head,
    *compile_first_terms,
    compile_variadic_term,
    *compile_last_terms
  ].compact.join(" &&\n") << SEQ_HEAD_GUARD
end

def compile_child_nb_guard

def compile_child_nb_guard
  fixed = first_terms_arity + last_terms_arity
  min = fixed + variadic_term_min_arity
  op = if @variadic_index
         max_variadic = @arities[@variadic_index].end
         if max_variadic != Float::INFINITY
           range = min..fixed + max_variadic
           return "(#{range}).cover?(#{CUR_NODE}.children.size)"
         end
         '>='
       else
         '=='
       end
  "#{CUR_NODE}.children.size #{op} #{min}"
end

def compile_first_terms

def compile_first_terms
  first_terms_range { |range| compile_terms(range, 0) }
end

def compile_last_terms

def compile_last_terms
  last_terms_range { |r| compile_terms(r, -last_terms_arity) }
end

def compile_seq_head

def compile_seq_head
  return unless seq_head?
  fail_due_to 'sequences can not start with <' \
    if @terms[0].respond_to? :call
  with_seq_head_context(@terms[0])
end

def compile_terms(index_range, start)

def compile_terms(index_range, start)
  index_range.map do |i|
    current = start
    start += @arities.fetch(i)
    term(i, current..start - 1)
  end
end

def compile_variadic_term

def compile_variadic_term
  variadic_arity { |arity| term(@variadic_index, arity) }
end

def first_terms_arity

def first_terms_arity
  first_terms_range { |r| @arities[r].inject(0, :+) } || 0
end

def first_terms_range

def first_terms_range
  yield 1..(@variadic_index || @terms.size) - 1 if seq_head?
end

def initialize(compiler, *arity_term_list)

def initialize(compiler, *arity_term_list)
  @arities, @terms = arity_term_list.transpose
  super(compiler)
  @variadic_index = @arities.find_index { |a| a.is_a?(Range) }
  fail_due_to 'multiple variable patterns in same sequence' \
    if @variadic_index && !@arities.one? { |a| a.is_a?(Range) }
end

def last_terms_arity

def last_terms_arity
  last_terms_range { |r| @arities[r].inject(0, :+) } || 0
end

def last_terms_range

def last_terms_range
  yield @variadic_index + 1...@terms.size if @variadic_index
end

def seq_head?

def seq_head?
  @variadic_index != 0
end

def term(index, range)

def term(index, range)
  t = @terms[index]
  if t.respond_to? :call
    t.call(range)
  else
    with_child_context(t, range.begin)
  end
end

def variadic_arity

def variadic_arity
  return unless @variadic_index
  first = @variadic_index.positive? ? first_terms_arity : SEQ_HEAD_INDEX
  yield first..-last_terms_arity - 1
end

def variadic_term_min_arity

def variadic_term_min_arity
  @variadic_index ? @arities[@variadic_index].begin : 0
end