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