# frozen_string_literal: true module RipperRubyParser module SexpHandlers # Utility methods used in several of the sexp handler modules module HelperMethods def extract_node_symbol_with_position(exp) _, ident, pos = exp.shift 3 return ident.to_sym, pos end def extract_node_symbol(exp) return nil if exp.nil? raise "Unexpected number of children: #{exp.length}" if exp.length != 2 _, ident = exp.shift 2 ident.to_sym end def with_position(pos, exp = nil) (line,) = pos exp = yield if exp.nil? with_line_number line, exp end def with_line_number(line, exp) exp.line = line exp end def with_position_from_node_symbol(exp) sym, pos = extract_node_symbol_with_position exp with_position(pos, yield(sym)) end def generic_add_star(exp) _, args, splatarg, *rest = shift_all exp items = process args items.push s(:splat, unwrap_begin(process(splatarg))) items.push(*map_process_list(rest)) end def integer_literal?(exp) exp && exp.sexp_type == :lit && exp[1].is_a?(Integer) end def reject_void_stmt(body) body.reject { |sub_exp| sub_exp.sexp_type == :void_stmt } end def map_process_list_compact(list) reject_void_stmt map_unwrap_begin_list map_process_list list end def map_process_list(list) list.map { |exp| process(exp) } end def map_unwrap_begin_list(list) list.map { |exp| unwrap_begin(exp) } end def unwrap_nil(exp) if exp.sexp_type == :void_stmt nil else exp end end def safe_unwrap_void_stmt(exp) unwrap_nil(exp) || s() end def unwrap_begin(exp) if exp.sexp_type == :begin exp[1] else exp end end def unwrap_block(exp) case exp.sexp_type when :block exp.sexp_body when :void_stmt [nil] else [exp] end end def wrap_in_block(statements, line) case statements.length when 0 s(:void_stmt).line(line) when 1 statements.first else first = statements.shift s(:block, *unwrap_block(first), *statements) end end def convert_void_stmt_to_nil_symbol(block) case block.sexp_type when :void_stmt s(:nil) else block end end def convert_empty_to_nil_symbol(block) case block.length when 0 s(:nil) else block end end def handle_return_argument_list(arglist) args = process(arglist).sexp_body case args.length when 0 args when 1 arg = args.first if arg.sexp_type == :splat s(:svalue, arg) else arg end else s(:array, *args) end end def shift_all(exp) [].tap do |result| result << exp.shift until exp.empty? end end end end end