rubocop 0.83.0 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +2 -2
 - data/config/default.yml +20 -3
 - data/lib/rubocop.rb +6 -59
 - data/lib/rubocop/ast_aliases.rb +8 -0
 - data/lib/rubocop/cli/command/show_cops.rb +2 -6
 - data/lib/rubocop/config.rb +1 -3
 - data/lib/rubocop/config_loader.rb +3 -9
 - data/lib/rubocop/config_loader_resolver.rb +2 -6
 - data/lib/rubocop/cop/autocorrect_logic.rb +1 -2
 - data/lib/rubocop/cop/corrector.rb +1 -3
 - data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -6
 - data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -3
 - data/lib/rubocop/cop/correctors/space_corrector.rb +1 -3
 - data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -3
 - data/lib/rubocop/cop/generator.rb +1 -1
 - data/lib/rubocop/cop/ignored_node.rb +1 -3
 - data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -6
 - data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +62 -4
 - data/lib/rubocop/cop/layout/first_argument_indentation.rb +0 -2
 - data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -3
 - data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -3
 - data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -6
 - data/lib/rubocop/cop/layout/indentation_width.rb +1 -3
 - data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -3
 - data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -3
 - data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -6
 - data/lib/rubocop/cop/layout/space_before_comment.rb +1 -3
 - data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -3
 - data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -6
 - data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -2
 - data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +133 -0
 - data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -6
 - data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +11 -3
 - data/lib/rubocop/cop/lint/percent_string_array.rb +1 -3
 - data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -1
 - data/lib/rubocop/cop/lint/syntax.rb +1 -3
 - data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -3
 - data/lib/rubocop/cop/migration/department_name.rb +5 -9
 - data/lib/rubocop/cop/mixin/alignment.rb +1 -3
 - data/lib/rubocop/cop/mixin/array_min_size.rb +2 -6
 - data/lib/rubocop/cop/mixin/check_line_breakable.rb +4 -12
 - data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -3
 - data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -3
 - data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -3
 - data/lib/rubocop/cop/mixin/surrounding_space.rb +1 -3
 - data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -3
 - data/lib/rubocop/cop/naming/file_name.rb +1 -3
 - data/lib/rubocop/cop/registry.rb +2 -6
 - data/lib/rubocop/cop/severity.rb +1 -3
 - data/lib/rubocop/cop/style/and_or.rb +2 -2
 - data/lib/rubocop/cop/style/attr.rb +1 -3
 - data/lib/rubocop/cop/style/block_delimiters.rb +2 -8
 - data/lib/rubocop/cop/style/conditional_assignment.rb +1 -3
 - data/lib/rubocop/cop/style/double_negation.rb +41 -4
 - data/lib/rubocop/cop/style/empty_literal.rb +1 -3
 - data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -4
 - data/lib/rubocop/cop/style/hash_syntax.rb +12 -5
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +1 -3
 - data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -3
 - data/lib/rubocop/cop/style/one_line_conditional.rb +2 -6
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -6
 - data/lib/rubocop/cop/style/safe_navigation.rb +2 -6
 - data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
 - data/lib/rubocop/cop/style/special_global_vars.rb +2 -6
 - data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -3
 - data/lib/rubocop/cop/style/trailing_underscore_variable.rb +2 -6
 - data/lib/rubocop/cop/variable_force.rb +3 -9
 - data/lib/rubocop/cop/variable_force/branch.rb +2 -6
 - data/lib/rubocop/cop/variable_force/variable.rb +2 -6
 - data/lib/rubocop/ext/processed_source.rb +18 -0
 - data/lib/rubocop/formatter/base_formatter.rb +0 -4
 - data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -12
 - data/lib/rubocop/formatter/formatter_set.rb +1 -3
 - data/lib/rubocop/options.rb +2 -8
 - data/lib/rubocop/remote_config.rb +1 -3
 - data/lib/rubocop/result_cache.rb +1 -3
 - data/lib/rubocop/rspec/cop_helper.rb +1 -3
 - data/lib/rubocop/rspec/expect_offense.rb +3 -9
 - data/lib/rubocop/rspec/shared_contexts.rb +54 -16
 - data/lib/rubocop/runner.rb +8 -10
 - data/lib/rubocop/target_finder.rb +2 -6
 - data/lib/rubocop/version.rb +5 -3
 - metadata +19 -56
 - data/lib/rubocop/ast/builder.rb +0 -85
 - data/lib/rubocop/ast/node.rb +0 -637
 - data/lib/rubocop/ast/node/alias_node.rb +0 -24
 - data/lib/rubocop/ast/node/and_node.rb +0 -29
 - data/lib/rubocop/ast/node/args_node.rb +0 -29
 - data/lib/rubocop/ast/node/array_node.rb +0 -70
 - data/lib/rubocop/ast/node/block_node.rb +0 -121
 - data/lib/rubocop/ast/node/break_node.rb +0 -17
 - data/lib/rubocop/ast/node/case_match_node.rb +0 -56
 - data/lib/rubocop/ast/node/case_node.rb +0 -56
 - data/lib/rubocop/ast/node/class_node.rb +0 -31
 - data/lib/rubocop/ast/node/def_node.rb +0 -82
 - data/lib/rubocop/ast/node/defined_node.rb +0 -17
 - data/lib/rubocop/ast/node/ensure_node.rb +0 -17
 - data/lib/rubocop/ast/node/float_node.rb +0 -12
 - data/lib/rubocop/ast/node/for_node.rb +0 -53
 - data/lib/rubocop/ast/node/forward_args_node.rb +0 -18
 - data/lib/rubocop/ast/node/hash_node.rb +0 -109
 - data/lib/rubocop/ast/node/if_node.rb +0 -175
 - data/lib/rubocop/ast/node/int_node.rb +0 -12
 - data/lib/rubocop/ast/node/keyword_splat_node.rb +0 -45
 - data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +0 -16
 - data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +0 -43
 - data/lib/rubocop/ast/node/mixin/collection_node.rb +0 -15
 - data/lib/rubocop/ast/node/mixin/conditional_node.rb +0 -45
 - data/lib/rubocop/ast/node/mixin/hash_element_node.rb +0 -125
 - data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -269
 - data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +0 -114
 - data/lib/rubocop/ast/node/mixin/modifier_node.rb +0 -17
 - data/lib/rubocop/ast/node/mixin/numeric_node.rb +0 -21
 - data/lib/rubocop/ast/node/mixin/parameterized_node.rb +0 -61
 - data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +0 -35
 - data/lib/rubocop/ast/node/module_node.rb +0 -24
 - data/lib/rubocop/ast/node/or_node.rb +0 -29
 - data/lib/rubocop/ast/node/pair_node.rb +0 -63
 - data/lib/rubocop/ast/node/range_node.rb +0 -18
 - data/lib/rubocop/ast/node/regexp_node.rb +0 -33
 - data/lib/rubocop/ast/node/resbody_node.rb +0 -24
 - data/lib/rubocop/ast/node/retry_node.rb +0 -17
 - data/lib/rubocop/ast/node/return_node.rb +0 -24
 - data/lib/rubocop/ast/node/self_class_node.rb +0 -24
 - data/lib/rubocop/ast/node/send_node.rb +0 -17
 - data/lib/rubocop/ast/node/str_node.rb +0 -16
 - data/lib/rubocop/ast/node/super_node.rb +0 -21
 - data/lib/rubocop/ast/node/symbol_node.rb +0 -12
 - data/lib/rubocop/ast/node/until_node.rb +0 -35
 - data/lib/rubocop/ast/node/when_node.rb +0 -53
 - data/lib/rubocop/ast/node/while_node.rb +0 -35
 - data/lib/rubocop/ast/node/yield_node.rb +0 -21
 - data/lib/rubocop/ast/sexp.rb +0 -16
 - data/lib/rubocop/ast/traversal.rb +0 -202
 - data/lib/rubocop/node_pattern.rb +0 -887
 - data/lib/rubocop/processed_source.rb +0 -213
 - data/lib/rubocop/token.rb +0 -114
 
    
        data/lib/rubocop/node_pattern.rb
    DELETED
    
    | 
         @@ -1,887 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'delegate'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'erb'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            # rubocop:disable Metrics/ClassLength, Metrics/CyclomaticComplexity
         
     | 
| 
       7 
     | 
    
         
            -
            module RuboCop
         
     | 
| 
       8 
     | 
    
         
            -
              # This class performs a pattern-matching operation on an AST node.
         
     | 
| 
       9 
     | 
    
         
            -
              #
         
     | 
| 
       10 
     | 
    
         
            -
              # Initialize a new `NodePattern` with `NodePattern.new(pattern_string)`, then
         
     | 
| 
       11 
     | 
    
         
            -
              # pass an AST node to `NodePattern#match`. Alternatively, use one of the class
         
     | 
| 
       12 
     | 
    
         
            -
              # macros in `NodePattern::Macros` to define your own pattern-matching method.
         
     | 
| 
       13 
     | 
    
         
            -
              #
         
     | 
| 
       14 
     | 
    
         
            -
              # If the match fails, `nil` will be returned. If the match succeeds, the
         
     | 
| 
       15 
     | 
    
         
            -
              # return value depends on whether a block was provided to `#match`, and
         
     | 
| 
       16 
     | 
    
         
            -
              # whether the pattern contained any "captures" (values which are extracted
         
     | 
| 
       17 
     | 
    
         
            -
              # from a matching AST.)
         
     | 
| 
       18 
     | 
    
         
            -
              #
         
     | 
| 
       19 
     | 
    
         
            -
              # - With block: #match yields the captures (if any) and passes the return
         
     | 
| 
       20 
     | 
    
         
            -
              #               value of the block through.
         
     | 
| 
       21 
     | 
    
         
            -
              # - With no block, but one capture: the capture is returned.
         
     | 
| 
       22 
     | 
    
         
            -
              # - With no block, but multiple captures: captures are returned as an array.
         
     | 
| 
       23 
     | 
    
         
            -
              # - With no block and no captures: #match returns `true`.
         
     | 
| 
       24 
     | 
    
         
            -
              #
         
     | 
| 
       25 
     | 
    
         
            -
              # ## Pattern string format examples
         
     | 
| 
       26 
     | 
    
         
            -
              #
         
     | 
| 
       27 
     | 
    
         
            -
              #     ':sym'              # matches a literal symbol
         
     | 
| 
       28 
     | 
    
         
            -
              #     '1'                 # matches a literal integer
         
     | 
| 
       29 
     | 
    
         
            -
              #     'nil'               # matches a literal nil
         
     | 
| 
       30 
     | 
    
         
            -
              #     'send'              # matches (send ...)
         
     | 
| 
       31 
     | 
    
         
            -
              #     '(send)'            # matches (send)
         
     | 
| 
       32 
     | 
    
         
            -
              #     '(send ...)'        # matches (send ...)
         
     | 
| 
       33 
     | 
    
         
            -
              #     '(op-asgn)'         # node types with hyphenated names also work
         
     | 
| 
       34 
     | 
    
         
            -
              #     '{send class}'      # matches (send ...) or (class ...)
         
     | 
| 
       35 
     | 
    
         
            -
              #     '({send class})'    # matches (send) or (class)
         
     | 
| 
       36 
     | 
    
         
            -
              #     '(send const)'      # matches (send (const ...))
         
     | 
| 
       37 
     | 
    
         
            -
              #     '(send _ :new)'     # matches (send <anything> :new)
         
     | 
| 
       38 
     | 
    
         
            -
              #     '(send $_ :new)'    # as above, but whatever matches the $_ is captured
         
     | 
| 
       39 
     | 
    
         
            -
              #     '(send $_ $_)'      # you can use as many captures as you want
         
     | 
| 
       40 
     | 
    
         
            -
              #     '(send !const ...)' # ! negates the next part of the pattern
         
     | 
| 
       41 
     | 
    
         
            -
              #     '$(send const ...)' # arbitrary matching can be performed on a capture
         
     | 
| 
       42 
     | 
    
         
            -
              #     '(send _recv _msg)' # wildcards can be named (for readability)
         
     | 
| 
       43 
     | 
    
         
            -
              #     '(send ... :new)'   # you can match against the last children
         
     | 
| 
       44 
     | 
    
         
            -
              #     '(array <str sym>)' # you can match children in any order. This
         
     | 
| 
       45 
     | 
    
         
            -
              #                         # would match `['x', :y]` as well as `[:y, 'x']
         
     | 
| 
       46 
     | 
    
         
            -
              #     '(_ <str sym ...>)' # will match if arguments have at least a `str` and
         
     | 
| 
       47 
     | 
    
         
            -
              #                         # a `sym` node, but can have more.
         
     | 
| 
       48 
     | 
    
         
            -
              #     '(array <$str $_>)' # captures are in the order of the pattern,
         
     | 
| 
       49 
     | 
    
         
            -
              #                         # irrespective of the actual order of the children
         
     | 
| 
       50 
     | 
    
         
            -
              #     '(array int*)'      # will match an array of 0 or more integers
         
     | 
| 
       51 
     | 
    
         
            -
              #     '(array int ?)'     # will match 0 or 1 integer.
         
     | 
| 
       52 
     | 
    
         
            -
              #                         # Note: Space needed to distinguish from int?
         
     | 
| 
       53 
     | 
    
         
            -
              #     '(array int+)'      # will match an array of 1 or more integers
         
     | 
| 
       54 
     | 
    
         
            -
              #     '(array (int $_)+)' # as above and will capture the numbers in an array
         
     | 
| 
       55 
     | 
    
         
            -
              #     '(send $...)'       # capture all the children as an array
         
     | 
| 
       56 
     | 
    
         
            -
              #     '(send $... int)'   # capture all children but the last as an array
         
     | 
| 
       57 
     | 
    
         
            -
              #     '(send _x :+ _x)'   # unification is performed on named wildcards
         
     | 
| 
       58 
     | 
    
         
            -
              #                         # (like Prolog variables...)
         
     | 
| 
       59 
     | 
    
         
            -
              #                         # (#== is used to see if values unify)
         
     | 
| 
       60 
     | 
    
         
            -
              #     '(int odd?)'        # words which end with a ? are predicate methods,
         
     | 
| 
       61 
     | 
    
         
            -
              #                         # are are called on the target to see if it matches
         
     | 
| 
       62 
     | 
    
         
            -
              #                         # any Ruby method which the matched object supports
         
     | 
| 
       63 
     | 
    
         
            -
              #                         # can be used
         
     | 
| 
       64 
     | 
    
         
            -
              #                         # if a truthy value is returned, the match succeeds
         
     | 
| 
       65 
     | 
    
         
            -
              #     '(int [!1 !2])'     # [] contains multiple patterns, ALL of which must
         
     | 
| 
       66 
     | 
    
         
            -
              #                         # match in that position
         
     | 
| 
       67 
     | 
    
         
            -
              #                         # in other words, while {} is pattern union (logical
         
     | 
| 
       68 
     | 
    
         
            -
              #                         # OR), [] is intersection (logical AND)
         
     | 
| 
       69 
     | 
    
         
            -
              #     '(send %1 _)'       # % stands for a parameter which must be supplied to
         
     | 
| 
       70 
     | 
    
         
            -
              #                         # #match at matching time
         
     | 
| 
       71 
     | 
    
         
            -
              #                         # it will be compared to the corresponding value in
         
     | 
| 
       72 
     | 
    
         
            -
              #                         # the AST using #==
         
     | 
| 
       73 
     | 
    
         
            -
              #                         # a bare '%' is the same as '%1'
         
     | 
| 
       74 
     | 
    
         
            -
              #                         # the number of extra parameters passed to #match
         
     | 
| 
       75 
     | 
    
         
            -
              #                         # must equal the highest % value in the pattern
         
     | 
| 
       76 
     | 
    
         
            -
              #                         # for consistency, %0 is the 'root node' which is
         
     | 
| 
       77 
     | 
    
         
            -
              #                         # passed as the 1st argument to #match, where the
         
     | 
| 
       78 
     | 
    
         
            -
              #                         # matching process starts
         
     | 
| 
       79 
     | 
    
         
            -
              #     '^^send'            # each ^ ascends one level in the AST
         
     | 
| 
       80 
     | 
    
         
            -
              #                         # so this matches against the grandparent node
         
     | 
| 
       81 
     | 
    
         
            -
              #     '`send'             # descends any number of level in the AST
         
     | 
| 
       82 
     | 
    
         
            -
              #                         # so this matches against any descendant node
         
     | 
| 
       83 
     | 
    
         
            -
              #     '#method'           # we call this a 'funcall'; it calls a method in the
         
     | 
| 
       84 
     | 
    
         
            -
              #                         # context where a pattern-matching method is defined
         
     | 
| 
       85 
     | 
    
         
            -
              #                         # if that returns a truthy value, the match succeeds
         
     | 
| 
       86 
     | 
    
         
            -
              #     'equal?(%1)'        # predicates can be given 1 or more extra args
         
     | 
| 
       87 
     | 
    
         
            -
              #     '#method(%0, 1)'    # funcalls can also be given 1 or more extra args
         
     | 
| 
       88 
     | 
    
         
            -
              #
         
     | 
| 
       89 
     | 
    
         
            -
              # You can nest arbitrarily deep:
         
     | 
| 
       90 
     | 
    
         
            -
              #
         
     | 
| 
       91 
     | 
    
         
            -
              #     # matches node parsed from 'Const = Class.new' or 'Const = Module.new':
         
     | 
| 
       92 
     | 
    
         
            -
              #     '(casgn nil? :Const (send (const nil? {:Class :Module}) :new))'
         
     | 
| 
       93 
     | 
    
         
            -
              #     # matches a node parsed from an 'if', with a '==' comparison,
         
     | 
| 
       94 
     | 
    
         
            -
              #     # and no 'else' branch:
         
     | 
| 
       95 
     | 
    
         
            -
              #     '(if (send _ :== _) _ nil?)'
         
     | 
| 
       96 
     | 
    
         
            -
              #
         
     | 
| 
       97 
     | 
    
         
            -
              # Note that patterns like 'send' are implemented by calling `#send_type?` on
         
     | 
| 
       98 
     | 
    
         
            -
              # the node being matched, 'const' by `#const_type?`, 'int' by `#int_type?`,
         
     | 
| 
       99 
     | 
    
         
            -
              # and so on. Therefore, if you add methods which are named like
         
     | 
| 
       100 
     | 
    
         
            -
              # `#prefix_type?` to the AST node class, then 'prefix' will become usable as
         
     | 
| 
       101 
     | 
    
         
            -
              # a pattern.
         
     | 
| 
       102 
     | 
    
         
            -
              #
         
     | 
| 
       103 
     | 
    
         
            -
              # Also note that if you need a "guard clause" to protect against possible nils
         
     | 
| 
       104 
     | 
    
         
            -
              # in a certain place in the AST, you can do it like this: `[!nil <pattern>]`
         
     | 
| 
       105 
     | 
    
         
            -
              #
         
     | 
| 
       106 
     | 
    
         
            -
              # The compiler code is very simple; don't be afraid to read through it!
         
     | 
| 
       107 
     | 
    
         
            -
              class NodePattern
         
     | 
| 
       108 
     | 
    
         
            -
                # @private
         
     | 
| 
       109 
     | 
    
         
            -
                Invalid = Class.new(StandardError)
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                # @private
         
     | 
| 
       112 
     | 
    
         
            -
                # Builds Ruby code which implements a pattern
         
     | 
| 
       113 
     | 
    
         
            -
                class Compiler
         
     | 
| 
       114 
     | 
    
         
            -
                  SYMBOL       = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
         
     | 
| 
       115 
     | 
    
         
            -
                  IDENTIFIER   = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
         
     | 
| 
       116 
     | 
    
         
            -
                  META         = Regexp.union(
         
     | 
| 
       117 
     | 
    
         
            -
                    %w"( ) { } [ ] $< < > $... $ ! ^ ` ... + * ?"
         
     | 
| 
       118 
     | 
    
         
            -
                  ).freeze
         
     | 
| 
       119 
     | 
    
         
            -
                  NUMBER       = /-?\d+(?:\.\d+)?/.freeze
         
     | 
| 
       120 
     | 
    
         
            -
                  STRING       = /".+?"/.freeze
         
     | 
| 
       121 
     | 
    
         
            -
                  METHOD_NAME  = /\#?#{IDENTIFIER}[\!\?]?\(?/.freeze
         
     | 
| 
       122 
     | 
    
         
            -
                  PARAM_NUMBER = /%\d*/.freeze
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
                  SEPARATORS = /[\s]+/.freeze
         
     | 
| 
       125 
     | 
    
         
            -
                  TOKENS     = Regexp.union(META, PARAM_NUMBER, NUMBER,
         
     | 
| 
       126 
     | 
    
         
            -
                                            METHOD_NAME, SYMBOL, STRING)
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
                  TOKEN = /\G(?:#{SEPARATORS}|#{TOKENS}|.)/.freeze
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
                  NODE      = /\A#{IDENTIFIER}\Z/.freeze
         
     | 
| 
       131 
     | 
    
         
            -
                  PREDICATE = /\A#{IDENTIFIER}\?\(?\Z/.freeze
         
     | 
| 
       132 
     | 
    
         
            -
                  WILDCARD  = /\A_(?:#{IDENTIFIER})?\Z/.freeze
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
                  FUNCALL   = /\A\##{METHOD_NAME}/.freeze
         
     | 
| 
       135 
     | 
    
         
            -
                  LITERAL   = /\A(?:#{SYMBOL}|#{NUMBER}|#{STRING})\Z/.freeze
         
     | 
| 
       136 
     | 
    
         
            -
                  PARAM     = /\A#{PARAM_NUMBER}\Z/.freeze
         
     | 
| 
       137 
     | 
    
         
            -
                  CLOSING   = /\A(?:\)|\}|\])\Z/.freeze
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
                  REST      = '...'
         
     | 
| 
       140 
     | 
    
         
            -
                  CAPTURED_REST = '$...'
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
                  attr_reader :match_code, :tokens, :captures
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                  SEQ_HEAD_INDEX = -1
         
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
                  # Placeholders while compiling, see with_..._context methods
         
     | 
| 
       147 
     | 
    
         
            -
                  CUR_PLACEHOLDER = '@@@cur'
         
     | 
| 
       148 
     | 
    
         
            -
                  CUR_NODE = "#{CUR_PLACEHOLDER} node@@@"
         
     | 
| 
       149 
     | 
    
         
            -
                  CUR_ELEMENT = "#{CUR_PLACEHOLDER} element@@@"
         
     | 
| 
       150 
     | 
    
         
            -
                  SEQ_HEAD_GUARD = '@@@seq guard head@@@'
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
                  line = __LINE__
         
     | 
| 
       153 
     | 
    
         
            -
                  ANY_ORDER_TEMPLATE = ERB.new <<~RUBY.gsub("-%>\n", '%>')
         
     | 
| 
       154 
     | 
    
         
            -
                    <% if capture_rest %>(<%= capture_rest %> = []) && <% end -%>
         
     | 
| 
       155 
     | 
    
         
            -
                    <% if capture_all %>(<%= capture_all %> = <% end -%>
         
     | 
| 
       156 
     | 
    
         
            -
                    <%= CUR_NODE %>.children[<%= range %>]<% if capture_all %>)<% end -%>
         
     | 
| 
       157 
     | 
    
         
            -
                    .each_with_object({}) { |<%= child %>, <%= matched %>|
         
     | 
| 
       158 
     | 
    
         
            -
                      case
         
     | 
| 
       159 
     | 
    
         
            -
                      <% patterns.each_with_index do |pattern, i| -%>
         
     | 
| 
       160 
     | 
    
         
            -
                      when !<%= matched %>[<%= i %>] && <%=
         
     | 
| 
       161 
     | 
    
         
            -
                        with_context(pattern, child, use_temp_node: false)
         
     | 
| 
       162 
     | 
    
         
            -
                      %> then <%= matched %>[<%= i %>] = true
         
     | 
| 
       163 
     | 
    
         
            -
                      <% end -%>
         
     | 
| 
       164 
     | 
    
         
            -
                      <% if !rest %>  else break({})
         
     | 
| 
       165 
     | 
    
         
            -
                      <% elsif capture_rest %>  else <%= capture_rest %> << <%= child %>
         
     | 
| 
       166 
     | 
    
         
            -
                      <% end -%>
         
     | 
| 
       167 
     | 
    
         
            -
                      end
         
     | 
| 
       168 
     | 
    
         
            -
                    }.size == <%= patterns.size -%>
         
     | 
| 
       169 
     | 
    
         
            -
                  RUBY
         
     | 
| 
       170 
     | 
    
         
            -
                  ANY_ORDER_TEMPLATE.location = [__FILE__, line + 1]
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
                  line = __LINE__
         
     | 
| 
       173 
     | 
    
         
            -
                  REPEATED_TEMPLATE = ERB.new <<~RUBY.gsub("-%>\n", '%>')
         
     | 
| 
       174 
     | 
    
         
            -
                    <% if captured %>(<%= accumulate %> = Array.new) && <% end %>
         
     | 
| 
       175 
     | 
    
         
            -
                    <%= CUR_NODE %>.children[<%= range %>].all? do |<%= child %>|
         
     | 
| 
       176 
     | 
    
         
            -
                      <%= with_context(expr, child, use_temp_node: false) %><% if captured %>&&
         
     | 
| 
       177 
     | 
    
         
            -
                      <%= accumulate %>.push(<%= captured %>)<% end %>
         
     | 
| 
       178 
     | 
    
         
            -
                    end <% if captured %>&&
         
     | 
| 
       179 
     | 
    
         
            -
                    (<%= captured %> = if <%= accumulate %>.empty?
         
     | 
| 
       180 
     | 
    
         
            -
                      <%= captured %>.map{[]} # Transpose hack won't work for empty case
         
     | 
| 
       181 
     | 
    
         
            -
                    else
         
     | 
| 
       182 
     | 
    
         
            -
                      <%= accumulate %>.transpose
         
     | 
| 
       183 
     | 
    
         
            -
                    end) <% end -%>
         
     | 
| 
       184 
     | 
    
         
            -
                  RUBY
         
     | 
| 
       185 
     | 
    
         
            -
                  REPEATED_TEMPLATE.location = [__FILE__, line + 1]
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                  def initialize(str, node_var = 'node0')
         
     | 
| 
       188 
     | 
    
         
            -
                    @string   = str
         
     | 
| 
       189 
     | 
    
         
            -
                    @root     = node_var
         
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
                    @temps    = 0  # avoid name clashes between temp variables
         
     | 
| 
       192 
     | 
    
         
            -
                    @captures = 0  # number of captures seen
         
     | 
| 
       193 
     | 
    
         
            -
                    @unify    = {} # named wildcard -> temp variable
         
     | 
| 
       194 
     | 
    
         
            -
                    @params   = 0  # highest % (param) number seen
         
     | 
| 
       195 
     | 
    
         
            -
                    run(node_var)
         
     | 
| 
       196 
     | 
    
         
            -
                  end
         
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                  def run(node_var)
         
     | 
| 
       199 
     | 
    
         
            -
                    @tokens = Compiler.tokens(@string)
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
                    @match_code = with_context(compile_expr, node_var, use_temp_node: false)
         
     | 
| 
       202 
     | 
    
         
            -
                    @match_code.prepend("(captures = Array.new(#{@captures})) && ") \
         
     | 
| 
       203 
     | 
    
         
            -
                      if @captures.positive?
         
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
       205 
     | 
    
         
            -
                    fail_due_to('unbalanced pattern') unless tokens.empty?
         
     | 
| 
       206 
     | 
    
         
            -
                  end
         
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
                  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       209 
     | 
    
         
            -
                  def compile_expr(token = tokens.shift)
         
     | 
| 
       210 
     | 
    
         
            -
                    # read a single pattern-matching expression from the token stream,
         
     | 
| 
       211 
     | 
    
         
            -
                    # return Ruby code which performs the corresponding matching operation
         
     | 
| 
       212 
     | 
    
         
            -
                    #
         
     | 
| 
       213 
     | 
    
         
            -
                    # the 'pattern-matching' expression may be a composite which
         
     | 
| 
       214 
     | 
    
         
            -
                    # contains an arbitrary number of sub-expressions, but that composite
         
     | 
| 
       215 
     | 
    
         
            -
                    # must all have precedence higher or equal to that of `&&`
         
     | 
| 
       216 
     | 
    
         
            -
                    #
         
     | 
| 
       217 
     | 
    
         
            -
                    # Expressions may use placeholders like:
         
     | 
| 
       218 
     | 
    
         
            -
                    #   CUR_NODE: Ruby code that evaluates to an AST node
         
     | 
| 
       219 
     | 
    
         
            -
                    #   CUR_ELEMENT: Either the node or the type if in first element of
         
     | 
| 
       220 
     | 
    
         
            -
                    #   a sequence (aka seq_head, e.g. "(seq_head first_node_arg ...")
         
     | 
| 
       221 
     | 
    
         
            -
                    case token
         
     | 
| 
       222 
     | 
    
         
            -
                    when '('       then compile_seq
         
     | 
| 
       223 
     | 
    
         
            -
                    when '{'       then compile_union
         
     | 
| 
       224 
     | 
    
         
            -
                    when '['       then compile_intersect
         
     | 
| 
       225 
     | 
    
         
            -
                    when '!'       then compile_negation
         
     | 
| 
       226 
     | 
    
         
            -
                    when '$'       then compile_capture
         
     | 
| 
       227 
     | 
    
         
            -
                    when '^'       then compile_ascend
         
     | 
| 
       228 
     | 
    
         
            -
                    when '`'       then compile_descend
         
     | 
| 
       229 
     | 
    
         
            -
                    when WILDCARD  then compile_wildcard(token[1..-1])
         
     | 
| 
       230 
     | 
    
         
            -
                    when FUNCALL   then compile_funcall(token)
         
     | 
| 
       231 
     | 
    
         
            -
                    when LITERAL   then compile_literal(token)
         
     | 
| 
       232 
     | 
    
         
            -
                    when PREDICATE then compile_predicate(token)
         
     | 
| 
       233 
     | 
    
         
            -
                    when NODE      then compile_nodetype(token)
         
     | 
| 
       234 
     | 
    
         
            -
                    when PARAM     then compile_param(token[1..-1])
         
     | 
| 
       235 
     | 
    
         
            -
                    when CLOSING   then fail_due_to("#{token} in invalid position")
         
     | 
| 
       236 
     | 
    
         
            -
                    when nil       then fail_due_to('pattern ended prematurely')
         
     | 
| 
       237 
     | 
    
         
            -
                    else                fail_due_to("invalid token #{token.inspect}")
         
     | 
| 
       238 
     | 
    
         
            -
                    end
         
     | 
| 
       239 
     | 
    
         
            -
                  end
         
     | 
| 
       240 
     | 
    
         
            -
                  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       241 
     | 
    
         
            -
             
     | 
| 
       242 
     | 
    
         
            -
                  def tokens_until(stop, what)
         
     | 
| 
       243 
     | 
    
         
            -
                    return to_enum __method__, stop, what unless block_given?
         
     | 
| 
       244 
     | 
    
         
            -
             
     | 
| 
       245 
     | 
    
         
            -
                    fail_due_to("empty #{what}") if tokens.first == stop && what
         
     | 
| 
       246 
     | 
    
         
            -
                    yield until tokens.first == stop
         
     | 
| 
       247 
     | 
    
         
            -
                    tokens.shift
         
     | 
| 
       248 
     | 
    
         
            -
                  end
         
     | 
| 
       249 
     | 
    
         
            -
             
     | 
| 
       250 
     | 
    
         
            -
                  def compile_seq
         
     | 
| 
       251 
     | 
    
         
            -
                    terms = tokens_until(')', 'sequence').map { variadic_seq_term }
         
     | 
| 
       252 
     | 
    
         
            -
                    Sequence.new(self, *terms).compile
         
     | 
| 
       253 
     | 
    
         
            -
                  end
         
     | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
       255 
     | 
    
         
            -
                  def compile_guard_clause
         
     | 
| 
       256 
     | 
    
         
            -
                    "#{CUR_NODE}.is_a?(RuboCop::AST::Node)"
         
     | 
| 
       257 
     | 
    
         
            -
                  end
         
     | 
| 
       258 
     | 
    
         
            -
             
     | 
| 
       259 
     | 
    
         
            -
                  def variadic_seq_term
         
     | 
| 
       260 
     | 
    
         
            -
                    token = tokens.shift
         
     | 
| 
       261 
     | 
    
         
            -
                    case token
         
     | 
| 
       262 
     | 
    
         
            -
                    when CAPTURED_REST then compile_captured_ellipsis
         
     | 
| 
       263 
     | 
    
         
            -
                    when REST          then compile_ellipsis
         
     | 
| 
       264 
     | 
    
         
            -
                    when '$<'          then compile_any_order(next_capture)
         
     | 
| 
       265 
     | 
    
         
            -
                    when '<'           then compile_any_order
         
     | 
| 
       266 
     | 
    
         
            -
                    else                    compile_repeated_expr(token)
         
     | 
| 
       267 
     | 
    
         
            -
                    end
         
     | 
| 
       268 
     | 
    
         
            -
                  end
         
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
                  def compile_repeated_expr(token)
         
     | 
| 
       271 
     | 
    
         
            -
                    before = @captures
         
     | 
| 
       272 
     | 
    
         
            -
                    expr = compile_expr(token)
         
     | 
| 
       273 
     | 
    
         
            -
                    min, max = parse_repetition_token
         
     | 
| 
       274 
     | 
    
         
            -
                    return [1, expr] if min.nil?
         
     | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
       276 
     | 
    
         
            -
                    if @captures != before
         
     | 
| 
       277 
     | 
    
         
            -
                      captured = "captures[#{before}...#{@captures}]"
         
     | 
| 
       278 
     | 
    
         
            -
                      accumulate = next_temp_variable(:accumulate)
         
     | 
| 
       279 
     | 
    
         
            -
                    end
         
     | 
| 
       280 
     | 
    
         
            -
                    arity = min..max || Float::INFINITY
         
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
       282 
     | 
    
         
            -
                    [arity, repeated_generator(expr, captured, accumulate)]
         
     | 
| 
       283 
     | 
    
         
            -
                  end
         
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
                  def repeated_generator(expr, captured, accumulate)
         
     | 
| 
       286 
     | 
    
         
            -
                    with_temp_variables do |child|
         
     | 
| 
       287 
     | 
    
         
            -
                      lambda do |range|
         
     | 
| 
       288 
     | 
    
         
            -
                        if range.begin == SEQ_HEAD_INDEX
         
     | 
| 
       289 
     | 
    
         
            -
                          fail_due_to 'repeated pattern at beginning of sequence'
         
     | 
| 
       290 
     | 
    
         
            -
                        end
         
     | 
| 
       291 
     | 
    
         
            -
                        REPEATED_TEMPLATE.result(binding)
         
     | 
| 
       292 
     | 
    
         
            -
                      end
         
     | 
| 
       293 
     | 
    
         
            -
                    end
         
     | 
| 
       294 
     | 
    
         
            -
                  end
         
     | 
| 
       295 
     | 
    
         
            -
             
     | 
| 
       296 
     | 
    
         
            -
                  def parse_repetition_token
         
     | 
| 
       297 
     | 
    
         
            -
                    case tokens.first
         
     | 
| 
       298 
     | 
    
         
            -
                    when '*' then min = 0
         
     | 
| 
       299 
     | 
    
         
            -
                    when '+' then min = 1
         
     | 
| 
       300 
     | 
    
         
            -
                    when '?' then min = 0
         
     | 
| 
       301 
     | 
    
         
            -
                                  max = 1
         
     | 
| 
       302 
     | 
    
         
            -
                    else          return
         
     | 
| 
       303 
     | 
    
         
            -
                    end
         
     | 
| 
       304 
     | 
    
         
            -
                    tokens.shift
         
     | 
| 
       305 
     | 
    
         
            -
                    [min, max]
         
     | 
| 
       306 
     | 
    
         
            -
                  end
         
     | 
| 
       307 
     | 
    
         
            -
             
     | 
| 
       308 
     | 
    
         
            -
                  # @private
         
     | 
| 
       309 
     | 
    
         
            -
                  # Builds Ruby code for a sequence
         
     | 
| 
       310 
     | 
    
         
            -
                  # (head *first_terms variadic_term *last_terms)
         
     | 
| 
       311 
     | 
    
         
            -
                  class Sequence < SimpleDelegator
         
     | 
| 
       312 
     | 
    
         
            -
                    def initialize(compiler, *arity_term_list)
         
     | 
| 
       313 
     | 
    
         
            -
                      @arities, @terms = arity_term_list.transpose
         
     | 
| 
       314 
     | 
    
         
            -
             
     | 
| 
       315 
     | 
    
         
            -
                      super(compiler)
         
     | 
| 
       316 
     | 
    
         
            -
                      @variadic_index = @arities.find_index { |a| a.is_a?(Range) }
         
     | 
| 
       317 
     | 
    
         
            -
                      fail_due_to 'multiple variable patterns in same sequence' \
         
     | 
| 
       318 
     | 
    
         
            -
                        if @variadic_index && !@arities.one? { |a| a.is_a?(Range) }
         
     | 
| 
       319 
     | 
    
         
            -
                    end
         
     | 
| 
       320 
     | 
    
         
            -
             
     | 
| 
       321 
     | 
    
         
            -
                    def compile
         
     | 
| 
       322 
     | 
    
         
            -
                      [
         
     | 
| 
       323 
     | 
    
         
            -
                        compile_guard_clause,
         
     | 
| 
       324 
     | 
    
         
            -
                        compile_child_nb_guard,
         
     | 
| 
       325 
     | 
    
         
            -
                        compile_seq_head,
         
     | 
| 
       326 
     | 
    
         
            -
                        *compile_first_terms,
         
     | 
| 
       327 
     | 
    
         
            -
                        compile_variadic_term,
         
     | 
| 
       328 
     | 
    
         
            -
                        *compile_last_terms
         
     | 
| 
       329 
     | 
    
         
            -
                      ].compact.join(" &&\n") << SEQ_HEAD_GUARD
         
     | 
| 
       330 
     | 
    
         
            -
                    end
         
     | 
| 
       331 
     | 
    
         
            -
             
     | 
| 
       332 
     | 
    
         
            -
                    private
         
     | 
| 
       333 
     | 
    
         
            -
             
     | 
| 
       334 
     | 
    
         
            -
                    def first_terms_arity
         
     | 
| 
       335 
     | 
    
         
            -
                      first_terms_range { |r| @arities[r].inject(0, :+) } || 0
         
     | 
| 
       336 
     | 
    
         
            -
                    end
         
     | 
| 
       337 
     | 
    
         
            -
             
     | 
| 
       338 
     | 
    
         
            -
                    def last_terms_arity
         
     | 
| 
       339 
     | 
    
         
            -
                      last_terms_range { |r| @arities[r].inject(0, :+) } || 0
         
     | 
| 
       340 
     | 
    
         
            -
                    end
         
     | 
| 
       341 
     | 
    
         
            -
             
     | 
| 
       342 
     | 
    
         
            -
                    def variadic_term_min_arity
         
     | 
| 
       343 
     | 
    
         
            -
                      @variadic_index ? @arities[@variadic_index].begin : 0
         
     | 
| 
       344 
     | 
    
         
            -
                    end
         
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
     | 
    
         
            -
                    def first_terms_range
         
     | 
| 
       347 
     | 
    
         
            -
                      yield 1..(@variadic_index || @terms.size) - 1 if seq_head?
         
     | 
| 
       348 
     | 
    
         
            -
                    end
         
     | 
| 
       349 
     | 
    
         
            -
             
     | 
| 
       350 
     | 
    
         
            -
                    def last_terms_range
         
     | 
| 
       351 
     | 
    
         
            -
                      yield @variadic_index + 1...@terms.size if @variadic_index
         
     | 
| 
       352 
     | 
    
         
            -
                    end
         
     | 
| 
       353 
     | 
    
         
            -
             
     | 
| 
       354 
     | 
    
         
            -
                    def seq_head?
         
     | 
| 
       355 
     | 
    
         
            -
                      @variadic_index != 0
         
     | 
| 
       356 
     | 
    
         
            -
                    end
         
     | 
| 
       357 
     | 
    
         
            -
             
     | 
| 
       358 
     | 
    
         
            -
                    def compile_child_nb_guard
         
     | 
| 
       359 
     | 
    
         
            -
                      fixed = first_terms_arity + last_terms_arity
         
     | 
| 
       360 
     | 
    
         
            -
                      min = fixed + variadic_term_min_arity
         
     | 
| 
       361 
     | 
    
         
            -
                      op = if @variadic_index
         
     | 
| 
       362 
     | 
    
         
            -
                             max_variadic = @arities[@variadic_index].end
         
     | 
| 
       363 
     | 
    
         
            -
                             if max_variadic != Float::INFINITY
         
     | 
| 
       364 
     | 
    
         
            -
                               range = min..fixed + max_variadic
         
     | 
| 
       365 
     | 
    
         
            -
                               return "(#{range}).cover?(#{CUR_NODE}.children.size)"
         
     | 
| 
       366 
     | 
    
         
            -
                             end
         
     | 
| 
       367 
     | 
    
         
            -
                             '>='
         
     | 
| 
       368 
     | 
    
         
            -
                           else
         
     | 
| 
       369 
     | 
    
         
            -
                             '=='
         
     | 
| 
       370 
     | 
    
         
            -
                           end
         
     | 
| 
       371 
     | 
    
         
            -
                      "#{CUR_NODE}.children.size #{op} #{min}"
         
     | 
| 
       372 
     | 
    
         
            -
                    end
         
     | 
| 
       373 
     | 
    
         
            -
             
     | 
| 
       374 
     | 
    
         
            -
                    def term(index, range)
         
     | 
| 
       375 
     | 
    
         
            -
                      t = @terms[index]
         
     | 
| 
       376 
     | 
    
         
            -
                      if t.respond_to? :call
         
     | 
| 
       377 
     | 
    
         
            -
                        t.call(range)
         
     | 
| 
       378 
     | 
    
         
            -
                      else
         
     | 
| 
       379 
     | 
    
         
            -
                        with_child_context(t, range.begin)
         
     | 
| 
       380 
     | 
    
         
            -
                      end
         
     | 
| 
       381 
     | 
    
         
            -
                    end
         
     | 
| 
       382 
     | 
    
         
            -
             
     | 
| 
       383 
     | 
    
         
            -
                    def compile_seq_head
         
     | 
| 
       384 
     | 
    
         
            -
                      return unless seq_head?
         
     | 
| 
       385 
     | 
    
         
            -
             
     | 
| 
       386 
     | 
    
         
            -
                      fail_due_to 'sequences cannot start with <' \
         
     | 
| 
       387 
     | 
    
         
            -
                        if @terms[0].respond_to? :call
         
     | 
| 
       388 
     | 
    
         
            -
             
     | 
| 
       389 
     | 
    
         
            -
                      with_seq_head_context(@terms[0])
         
     | 
| 
       390 
     | 
    
         
            -
                    end
         
     | 
| 
       391 
     | 
    
         
            -
             
     | 
| 
       392 
     | 
    
         
            -
                    def compile_first_terms
         
     | 
| 
       393 
     | 
    
         
            -
                      first_terms_range { |range| compile_terms(range, 0) }
         
     | 
| 
       394 
     | 
    
         
            -
                    end
         
     | 
| 
       395 
     | 
    
         
            -
             
     | 
| 
       396 
     | 
    
         
            -
                    def compile_last_terms
         
     | 
| 
       397 
     | 
    
         
            -
                      last_terms_range { |r| compile_terms(r, -last_terms_arity) }
         
     | 
| 
       398 
     | 
    
         
            -
                    end
         
     | 
| 
       399 
     | 
    
         
            -
             
     | 
| 
       400 
     | 
    
         
            -
                    def compile_terms(index_range, start)
         
     | 
| 
       401 
     | 
    
         
            -
                      index_range.map do |i|
         
     | 
| 
       402 
     | 
    
         
            -
                        current = start
         
     | 
| 
       403 
     | 
    
         
            -
                        start += @arities.fetch(i)
         
     | 
| 
       404 
     | 
    
         
            -
                        term(i, current..start - 1)
         
     | 
| 
       405 
     | 
    
         
            -
                      end
         
     | 
| 
       406 
     | 
    
         
            -
                    end
         
     | 
| 
       407 
     | 
    
         
            -
             
     | 
| 
       408 
     | 
    
         
            -
                    def compile_variadic_term
         
     | 
| 
       409 
     | 
    
         
            -
                      variadic_arity { |arity| term(@variadic_index, arity) }
         
     | 
| 
       410 
     | 
    
         
            -
                    end
         
     | 
| 
       411 
     | 
    
         
            -
             
     | 
| 
       412 
     | 
    
         
            -
                    def variadic_arity
         
     | 
| 
       413 
     | 
    
         
            -
                      return unless @variadic_index
         
     | 
| 
       414 
     | 
    
         
            -
             
     | 
| 
       415 
     | 
    
         
            -
                      first = @variadic_index.positive? ? first_terms_arity : SEQ_HEAD_INDEX
         
     | 
| 
       416 
     | 
    
         
            -
                      yield first..-last_terms_arity - 1
         
     | 
| 
       417 
     | 
    
         
            -
                    end
         
     | 
| 
       418 
     | 
    
         
            -
                  end
         
     | 
| 
       419 
     | 
    
         
            -
                  private_constant :Sequence
         
     | 
| 
       420 
     | 
    
         
            -
             
     | 
| 
       421 
     | 
    
         
            -
                  def compile_captured_ellipsis
         
     | 
| 
       422 
     | 
    
         
            -
                    capture = next_capture
         
     | 
| 
       423 
     | 
    
         
            -
                    block = lambda { |range|
         
     | 
| 
       424 
     | 
    
         
            -
                      # Consider ($...) like (_ $...):
         
     | 
| 
       425 
     | 
    
         
            -
                      range = 0..range.end if range.begin == SEQ_HEAD_INDEX
         
     | 
| 
       426 
     | 
    
         
            -
                      "(#{capture} = #{CUR_NODE}.children[#{range}])"
         
     | 
| 
       427 
     | 
    
         
            -
                    }
         
     | 
| 
       428 
     | 
    
         
            -
                    [0..Float::INFINITY, block]
         
     | 
| 
       429 
     | 
    
         
            -
                  end
         
     | 
| 
       430 
     | 
    
         
            -
             
     | 
| 
       431 
     | 
    
         
            -
                  def compile_ellipsis
         
     | 
| 
       432 
     | 
    
         
            -
                    [0..Float::INFINITY, 'true']
         
     | 
| 
       433 
     | 
    
         
            -
                  end
         
     | 
| 
       434 
     | 
    
         
            -
             
     | 
| 
       435 
     | 
    
         
            -
                  # rubocop:disable Metrics/AbcSize
         
     | 
| 
       436 
     | 
    
         
            -
                  # rubocop:disable Metrics/MethodLength
         
     | 
| 
       437 
     | 
    
         
            -
                  def compile_any_order(capture_all = nil)
         
     | 
| 
       438 
     | 
    
         
            -
                    rest = capture_rest = nil
         
     | 
| 
       439 
     | 
    
         
            -
                    patterns = []
         
     | 
| 
       440 
     | 
    
         
            -
                    with_temp_variables do |child, matched|
         
     | 
| 
       441 
     | 
    
         
            -
                      tokens_until('>', 'any child') do
         
     | 
| 
       442 
     | 
    
         
            -
                        fail_due_to 'ellipsis must be at the end of <>' if rest
         
     | 
| 
       443 
     | 
    
         
            -
                        token = tokens.shift
         
     | 
| 
       444 
     | 
    
         
            -
                        case token
         
     | 
| 
       445 
     | 
    
         
            -
                        when CAPTURED_REST then rest = capture_rest = next_capture
         
     | 
| 
       446 
     | 
    
         
            -
                        when REST          then rest = true
         
     | 
| 
       447 
     | 
    
         
            -
                        else patterns << compile_expr(token)
         
     | 
| 
       448 
     | 
    
         
            -
                        end
         
     | 
| 
       449 
     | 
    
         
            -
                      end
         
     | 
| 
       450 
     | 
    
         
            -
                      [rest ? patterns.size..Float::INFINITY : patterns.size,
         
     | 
| 
       451 
     | 
    
         
            -
                       ->(range) { ANY_ORDER_TEMPLATE.result(binding) }]
         
     | 
| 
       452 
     | 
    
         
            -
                    end
         
     | 
| 
       453 
     | 
    
         
            -
                  end
         
     | 
| 
       454 
     | 
    
         
            -
                  # rubocop:enable Metrics/MethodLength
         
     | 
| 
       455 
     | 
    
         
            -
                  # rubocop:enable Metrics/AbcSize
         
     | 
| 
       456 
     | 
    
         
            -
             
     | 
| 
       457 
     | 
    
         
            -
                  def insure_same_captures(enum, what)
         
     | 
| 
       458 
     | 
    
         
            -
                    return to_enum __method__, enum, what unless block_given?
         
     | 
| 
       459 
     | 
    
         
            -
             
     | 
| 
       460 
     | 
    
         
            -
                    captures_before = captures_after = nil
         
     | 
| 
       461 
     | 
    
         
            -
                    enum.each do
         
     | 
| 
       462 
     | 
    
         
            -
                      captures_before ||= @captures
         
     | 
| 
       463 
     | 
    
         
            -
                      @captures = captures_before
         
     | 
| 
       464 
     | 
    
         
            -
                      yield
         
     | 
| 
       465 
     | 
    
         
            -
                      captures_after ||= @captures
         
     | 
| 
       466 
     | 
    
         
            -
                      if captures_after != @captures
         
     | 
| 
       467 
     | 
    
         
            -
                        fail_due_to("each #{what} must have same # of captures")
         
     | 
| 
       468 
     | 
    
         
            -
                      end
         
     | 
| 
       469 
     | 
    
         
            -
                    end
         
     | 
| 
       470 
     | 
    
         
            -
                  end
         
     | 
| 
       471 
     | 
    
         
            -
             
     | 
| 
       472 
     | 
    
         
            -
                  def access_unify(name)
         
     | 
| 
       473 
     | 
    
         
            -
                    var = @unify[name]
         
     | 
| 
       474 
     | 
    
         
            -
             
     | 
| 
       475 
     | 
    
         
            -
                    if var == :forbidden_unification
         
     | 
| 
       476 
     | 
    
         
            -
                      fail_due_to "Wildcard #{name} was first seen in a subset of a" \
         
     | 
| 
       477 
     | 
    
         
            -
                                  " union and can't be used outside that union"
         
     | 
| 
       478 
     | 
    
         
            -
                    end
         
     | 
| 
       479 
     | 
    
         
            -
                    var
         
     | 
| 
       480 
     | 
    
         
            -
                  end
         
     | 
| 
       481 
     | 
    
         
            -
             
     | 
| 
       482 
     | 
    
         
            -
                  def forbid_unification(*names)
         
     | 
| 
       483 
     | 
    
         
            -
                    names.each do |name|
         
     | 
| 
       484 
     | 
    
         
            -
                      @unify[name] = :forbidden_unification
         
     | 
| 
       485 
     | 
    
         
            -
                    end
         
     | 
| 
       486 
     | 
    
         
            -
                  end
         
     | 
| 
       487 
     | 
    
         
            -
             
     | 
| 
       488 
     | 
    
         
            -
                  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       489 
     | 
    
         
            -
                  def unify_in_union(enum)
         
     | 
| 
       490 
     | 
    
         
            -
                    # We need to reset @unify before each branch is processed.
         
     | 
| 
       491 
     | 
    
         
            -
                    # Moreover we need to keep track of newly encountered wildcards.
         
     | 
| 
       492 
     | 
    
         
            -
                    # Var `new_unify_intersection` will hold those that are encountered
         
     | 
| 
       493 
     | 
    
         
            -
                    # in all branches; these are not a problem.
         
     | 
| 
       494 
     | 
    
         
            -
                    # Var `partial_unify` will hold those encountered in only a subset
         
     | 
| 
       495 
     | 
    
         
            -
                    # of the branches; these can't be used outside of the union.
         
     | 
| 
       496 
     | 
    
         
            -
             
     | 
| 
       497 
     | 
    
         
            -
                    return to_enum __method__, enum unless block_given?
         
     | 
| 
       498 
     | 
    
         
            -
             
     | 
| 
       499 
     | 
    
         
            -
                    new_unify_intersection = nil
         
     | 
| 
       500 
     | 
    
         
            -
                    partial_unify = []
         
     | 
| 
       501 
     | 
    
         
            -
                    unify_before = @unify.dup
         
     | 
| 
       502 
     | 
    
         
            -
             
     | 
| 
       503 
     | 
    
         
            -
                    result = enum.each do |e|
         
     | 
| 
       504 
     | 
    
         
            -
                      @unify = unify_before.dup if new_unify_intersection
         
     | 
| 
       505 
     | 
    
         
            -
                      yield e
         
     | 
| 
       506 
     | 
    
         
            -
                      new_unify = @unify.keys - unify_before.keys
         
     | 
| 
       507 
     | 
    
         
            -
                      if new_unify_intersection.nil?
         
     | 
| 
       508 
     | 
    
         
            -
                        # First iteration
         
     | 
| 
       509 
     | 
    
         
            -
                        new_unify_intersection = new_unify
         
     | 
| 
       510 
     | 
    
         
            -
                      else
         
     | 
| 
       511 
     | 
    
         
            -
                        union = new_unify_intersection | new_unify
         
     | 
| 
       512 
     | 
    
         
            -
                        new_unify_intersection &= new_unify
         
     | 
| 
       513 
     | 
    
         
            -
                        partial_unify |= union - new_unify_intersection
         
     | 
| 
       514 
     | 
    
         
            -
                      end
         
     | 
| 
       515 
     | 
    
         
            -
                    end
         
     | 
| 
       516 
     | 
    
         
            -
             
     | 
| 
       517 
     | 
    
         
            -
                    # At this point, all members of `new_unify_intersection` can be used
         
     | 
| 
       518 
     | 
    
         
            -
                    # for unification outside of the union, but partial_unify may not
         
     | 
| 
       519 
     | 
    
         
            -
             
     | 
| 
       520 
     | 
    
         
            -
                    forbid_unification(*partial_unify)
         
     | 
| 
       521 
     | 
    
         
            -
             
     | 
| 
       522 
     | 
    
         
            -
                    result
         
     | 
| 
       523 
     | 
    
         
            -
                  end
         
     | 
| 
       524 
     | 
    
         
            -
                  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       525 
     | 
    
         
            -
             
     | 
| 
       526 
     | 
    
         
            -
                  def compile_union
         
     | 
| 
       527 
     | 
    
         
            -
                    # we need to ensure that each branch of the {} contains the same
         
     | 
| 
       528 
     | 
    
         
            -
                    # number of captures (since only one branch of the {} can actually
         
     | 
| 
       529 
     | 
    
         
            -
                    # match, the same variables are used to hold the captures for each
         
     | 
| 
       530 
     | 
    
         
            -
                    # branch)
         
     | 
| 
       531 
     | 
    
         
            -
                    enum = tokens_until('}', 'union')
         
     | 
| 
       532 
     | 
    
         
            -
                    enum = unify_in_union(enum)
         
     | 
| 
       533 
     | 
    
         
            -
                    terms = insure_same_captures(enum, 'branch of {}')
         
     | 
| 
       534 
     | 
    
         
            -
                            .map { compile_expr }
         
     | 
| 
       535 
     | 
    
         
            -
             
     | 
| 
       536 
     | 
    
         
            -
                    "(#{terms.join(' || ')})"
         
     | 
| 
       537 
     | 
    
         
            -
                  end
         
     | 
| 
       538 
     | 
    
         
            -
             
     | 
| 
       539 
     | 
    
         
            -
                  def compile_intersect
         
     | 
| 
       540 
     | 
    
         
            -
                    tokens_until(']', 'intersection')
         
     | 
| 
       541 
     | 
    
         
            -
                      .map { compile_expr }
         
     | 
| 
       542 
     | 
    
         
            -
                      .join(' && ')
         
     | 
| 
       543 
     | 
    
         
            -
                  end
         
     | 
| 
       544 
     | 
    
         
            -
             
     | 
| 
       545 
     | 
    
         
            -
                  def compile_capture
         
     | 
| 
       546 
     | 
    
         
            -
                    "(#{next_capture} = #{CUR_ELEMENT}; #{compile_expr})"
         
     | 
| 
       547 
     | 
    
         
            -
                  end
         
     | 
| 
       548 
     | 
    
         
            -
             
     | 
| 
       549 
     | 
    
         
            -
                  def compile_negation
         
     | 
| 
       550 
     | 
    
         
            -
                    "!(#{compile_expr})"
         
     | 
| 
       551 
     | 
    
         
            -
                  end
         
     | 
| 
       552 
     | 
    
         
            -
             
     | 
| 
       553 
     | 
    
         
            -
                  def compile_ascend
         
     | 
| 
       554 
     | 
    
         
            -
                    with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
         
     | 
| 
       555 
     | 
    
         
            -
                  end
         
     | 
| 
       556 
     | 
    
         
            -
             
     | 
| 
       557 
     | 
    
         
            -
                  def compile_descend
         
     | 
| 
       558 
     | 
    
         
            -
                    with_temp_variables do |descendant|
         
     | 
| 
       559 
     | 
    
         
            -
                      pattern = with_context(compile_expr, descendant,
         
     | 
| 
       560 
     | 
    
         
            -
                                             use_temp_node: false)
         
     | 
| 
       561 
     | 
    
         
            -
                      [
         
     | 
| 
       562 
     | 
    
         
            -
                        "RuboCop::NodePattern.descend(#{CUR_ELEMENT}).",
         
     | 
| 
       563 
     | 
    
         
            -
                        "any? do |#{descendant}|",
         
     | 
| 
       564 
     | 
    
         
            -
                        "  #{pattern}",
         
     | 
| 
       565 
     | 
    
         
            -
                        'end'
         
     | 
| 
       566 
     | 
    
         
            -
                      ].join("\n")
         
     | 
| 
       567 
     | 
    
         
            -
                    end
         
     | 
| 
       568 
     | 
    
         
            -
                  end
         
     | 
| 
       569 
     | 
    
         
            -
             
     | 
| 
       570 
     | 
    
         
            -
                  def compile_wildcard(name)
         
     | 
| 
       571 
     | 
    
         
            -
                    if name.empty?
         
     | 
| 
       572 
     | 
    
         
            -
                      'true'
         
     | 
| 
       573 
     | 
    
         
            -
                    elsif @unify.key?(name)
         
     | 
| 
       574 
     | 
    
         
            -
                      # we have already seen a wildcard with this name before
         
     | 
| 
       575 
     | 
    
         
            -
                      # so the value it matched the first time will already be stored
         
     | 
| 
       576 
     | 
    
         
            -
                      # in a temp. check if this value matches the one stored in the temp
         
     | 
| 
       577 
     | 
    
         
            -
                      "#{CUR_ELEMENT} == #{access_unify(name)}"
         
     | 
| 
       578 
     | 
    
         
            -
                    else
         
     | 
| 
       579 
     | 
    
         
            -
                      n = @unify[name] = "unify_#{name.gsub('-', '__')}"
         
     | 
| 
       580 
     | 
    
         
            -
                      # double assign to avoid "assigned but unused variable"
         
     | 
| 
       581 
     | 
    
         
            -
                      "(#{n} = #{CUR_ELEMENT}; " \
         
     | 
| 
       582 
     | 
    
         
            -
                      "#{n} = #{n}; true)"
         
     | 
| 
       583 
     | 
    
         
            -
                    end
         
     | 
| 
       584 
     | 
    
         
            -
                  end
         
     | 
| 
       585 
     | 
    
         
            -
             
     | 
| 
       586 
     | 
    
         
            -
                  def compile_literal(literal)
         
     | 
| 
       587 
     | 
    
         
            -
                    "#{CUR_ELEMENT} == #{literal}"
         
     | 
| 
       588 
     | 
    
         
            -
                  end
         
     | 
| 
       589 
     | 
    
         
            -
             
     | 
| 
       590 
     | 
    
         
            -
                  def compile_predicate(predicate)
         
     | 
| 
       591 
     | 
    
         
            -
                    if predicate.end_with?('(') # is there an arglist?
         
     | 
| 
       592 
     | 
    
         
            -
                      args = compile_args(tokens)
         
     | 
| 
       593 
     | 
    
         
            -
                      predicate = predicate[0..-2] # drop the trailing (
         
     | 
| 
       594 
     | 
    
         
            -
                      "#{CUR_ELEMENT}.#{predicate}(#{args.join(',')})"
         
     | 
| 
       595 
     | 
    
         
            -
                    else
         
     | 
| 
       596 
     | 
    
         
            -
                      "#{CUR_ELEMENT}.#{predicate}"
         
     | 
| 
       597 
     | 
    
         
            -
                    end
         
     | 
| 
       598 
     | 
    
         
            -
                  end
         
     | 
| 
       599 
     | 
    
         
            -
             
     | 
| 
       600 
     | 
    
         
            -
                  def compile_funcall(method)
         
     | 
| 
       601 
     | 
    
         
            -
                    # call a method in the context which this pattern-matching
         
     | 
| 
       602 
     | 
    
         
            -
                    # code is used in. pass target value as an argument
         
     | 
| 
       603 
     | 
    
         
            -
                    method = method[1..-1] # drop the leading #
         
     | 
| 
       604 
     | 
    
         
            -
                    if method.end_with?('(') # is there an arglist?
         
     | 
| 
       605 
     | 
    
         
            -
                      args = compile_args(tokens)
         
     | 
| 
       606 
     | 
    
         
            -
                      method = method[0..-2] # drop the trailing (
         
     | 
| 
       607 
     | 
    
         
            -
                      "#{method}(#{CUR_ELEMENT},#{args.join(',')})"
         
     | 
| 
       608 
     | 
    
         
            -
                    else
         
     | 
| 
       609 
     | 
    
         
            -
                      "#{method}(#{CUR_ELEMENT})"
         
     | 
| 
       610 
     | 
    
         
            -
                    end
         
     | 
| 
       611 
     | 
    
         
            -
                  end
         
     | 
| 
       612 
     | 
    
         
            -
             
     | 
| 
       613 
     | 
    
         
            -
                  def compile_nodetype(type)
         
     | 
| 
       614 
     | 
    
         
            -
                    "#{compile_guard_clause} && #{CUR_NODE}.#{type.tr('-', '_')}_type?"
         
     | 
| 
       615 
     | 
    
         
            -
                  end
         
     | 
| 
       616 
     | 
    
         
            -
             
     | 
| 
       617 
     | 
    
         
            -
                  def compile_param(number)
         
     | 
| 
       618 
     | 
    
         
            -
                    "#{CUR_ELEMENT} == #{get_param(number)}"
         
     | 
| 
       619 
     | 
    
         
            -
                  end
         
     | 
| 
       620 
     | 
    
         
            -
             
     | 
| 
       621 
     | 
    
         
            -
                  def compile_args(tokens)
         
     | 
| 
       622 
     | 
    
         
            -
                    index = tokens.find_index { |token| token == ')' }
         
     | 
| 
       623 
     | 
    
         
            -
             
     | 
| 
       624 
     | 
    
         
            -
                    tokens.slice!(0..index).each_with_object([]) do |token, args|
         
     | 
| 
       625 
     | 
    
         
            -
                      next if [')', ','].include?(token)
         
     | 
| 
       626 
     | 
    
         
            -
             
     | 
| 
       627 
     | 
    
         
            -
                      args << compile_arg(token)
         
     | 
| 
       628 
     | 
    
         
            -
                    end
         
     | 
| 
       629 
     | 
    
         
            -
                  end
         
     | 
| 
       630 
     | 
    
         
            -
             
     | 
| 
       631 
     | 
    
         
            -
                  def compile_arg(token)
         
     | 
| 
       632 
     | 
    
         
            -
                    case token
         
     | 
| 
       633 
     | 
    
         
            -
                    when WILDCARD  then
         
     | 
| 
       634 
     | 
    
         
            -
                      name = token[1..-1]
         
     | 
| 
       635 
     | 
    
         
            -
                      access_unify(name) || fail_due_to('invalid in arglist: ' + token)
         
     | 
| 
       636 
     | 
    
         
            -
                    when LITERAL   then token
         
     | 
| 
       637 
     | 
    
         
            -
                    when PARAM     then get_param(token[1..-1])
         
     | 
| 
       638 
     | 
    
         
            -
                    when CLOSING   then fail_due_to("#{token} in invalid position")
         
     | 
| 
       639 
     | 
    
         
            -
                    when nil       then fail_due_to('pattern ended prematurely')
         
     | 
| 
       640 
     | 
    
         
            -
                    else fail_due_to("invalid token in arglist: #{token.inspect}")
         
     | 
| 
       641 
     | 
    
         
            -
                    end
         
     | 
| 
       642 
     | 
    
         
            -
                  end
         
     | 
| 
       643 
     | 
    
         
            -
             
     | 
| 
       644 
     | 
    
         
            -
                  def next_capture
         
     | 
| 
       645 
     | 
    
         
            -
                    index = @captures
         
     | 
| 
       646 
     | 
    
         
            -
                    @captures += 1
         
     | 
| 
       647 
     | 
    
         
            -
                    "captures[#{index}]"
         
     | 
| 
       648 
     | 
    
         
            -
                  end
         
     | 
| 
       649 
     | 
    
         
            -
             
     | 
| 
       650 
     | 
    
         
            -
                  def get_param(number)
         
     | 
| 
       651 
     | 
    
         
            -
                    number = number.empty? ? 1 : Integer(number)
         
     | 
| 
       652 
     | 
    
         
            -
                    @params = number if number > @params
         
     | 
| 
       653 
     | 
    
         
            -
                    number.zero? ? @root : "param#{number}"
         
     | 
| 
       654 
     | 
    
         
            -
                  end
         
     | 
| 
       655 
     | 
    
         
            -
             
     | 
| 
       656 
     | 
    
         
            -
                  def emit_yield_capture(when_no_capture = '')
         
     | 
| 
       657 
     | 
    
         
            -
                    yield_val = if @captures.zero?
         
     | 
| 
       658 
     | 
    
         
            -
                                  when_no_capture
         
     | 
| 
       659 
     | 
    
         
            -
                                elsif @captures == 1
         
     | 
| 
       660 
     | 
    
         
            -
                                  'captures[0]' # Circumvent https://github.com/jruby/jruby/issues/5710
         
     | 
| 
       661 
     | 
    
         
            -
                                else
         
     | 
| 
       662 
     | 
    
         
            -
                                  '*captures'
         
     | 
| 
       663 
     | 
    
         
            -
                                end
         
     | 
| 
       664 
     | 
    
         
            -
                    "yield(#{yield_val})"
         
     | 
| 
       665 
     | 
    
         
            -
                  end
         
     | 
| 
       666 
     | 
    
         
            -
             
     | 
| 
       667 
     | 
    
         
            -
                  def emit_retval
         
     | 
| 
       668 
     | 
    
         
            -
                    if @captures.zero?
         
     | 
| 
       669 
     | 
    
         
            -
                      'true'
         
     | 
| 
       670 
     | 
    
         
            -
                    elsif @captures == 1
         
     | 
| 
       671 
     | 
    
         
            -
                      'captures[0]'
         
     | 
| 
       672 
     | 
    
         
            -
                    else
         
     | 
| 
       673 
     | 
    
         
            -
                      'captures'
         
     | 
| 
       674 
     | 
    
         
            -
                    end
         
     | 
| 
       675 
     | 
    
         
            -
                  end
         
     | 
| 
       676 
     | 
    
         
            -
             
     | 
| 
       677 
     | 
    
         
            -
                  def emit_param_list
         
     | 
| 
       678 
     | 
    
         
            -
                    (1..@params).map { |n| "param#{n}" }.join(',')
         
     | 
| 
       679 
     | 
    
         
            -
                  end
         
     | 
| 
       680 
     | 
    
         
            -
             
     | 
| 
       681 
     | 
    
         
            -
                  def emit_trailing_params
         
     | 
| 
       682 
     | 
    
         
            -
                    params = emit_param_list
         
     | 
| 
       683 
     | 
    
         
            -
                    params.empty? ? '' : ",#{params}"
         
     | 
| 
       684 
     | 
    
         
            -
                  end
         
     | 
| 
       685 
     | 
    
         
            -
             
     | 
| 
       686 
     | 
    
         
            -
                  def emit_method_code
         
     | 
| 
       687 
     | 
    
         
            -
                    <<~RUBY
         
     | 
| 
       688 
     | 
    
         
            -
                      return unless #{@match_code}
         
     | 
| 
       689 
     | 
    
         
            -
                      block_given? ? #{emit_yield_capture} : (return #{emit_retval})
         
     | 
| 
       690 
     | 
    
         
            -
                    RUBY
         
     | 
| 
       691 
     | 
    
         
            -
                  end
         
     | 
| 
       692 
     | 
    
         
            -
             
     | 
| 
       693 
     | 
    
         
            -
                  def fail_due_to(message)
         
     | 
| 
       694 
     | 
    
         
            -
                    raise Invalid, "Couldn't compile due to #{message}. Pattern: #{@string}"
         
     | 
| 
       695 
     | 
    
         
            -
                  end
         
     | 
| 
       696 
     | 
    
         
            -
             
     | 
| 
       697 
     | 
    
         
            -
                  def with_temp_node(cur_node)
         
     | 
| 
       698 
     | 
    
         
            -
                    with_temp_variables do |node|
         
     | 
| 
       699 
     | 
    
         
            -
                      yield "(#{node} = #{cur_node})", node
         
     | 
| 
       700 
     | 
    
         
            -
                    end
         
     | 
| 
       701 
     | 
    
         
            -
                      .gsub("\n", "\n  ") # Nicer indent for debugging
         
     | 
| 
       702 
     | 
    
         
            -
                  end
         
     | 
| 
       703 
     | 
    
         
            -
             
     | 
| 
       704 
     | 
    
         
            -
                  def with_temp_variables(&block)
         
     | 
| 
       705 
     | 
    
         
            -
                    names = block.parameters.map { |_, name| next_temp_variable(name) }
         
     | 
| 
       706 
     | 
    
         
            -
                    yield(*names)
         
     | 
| 
       707 
     | 
    
         
            -
                  end
         
     | 
| 
       708 
     | 
    
         
            -
             
     | 
| 
       709 
     | 
    
         
            -
                  def next_temp_variable(name)
         
     | 
| 
       710 
     | 
    
         
            -
                    "#{name}#{next_temp_value}"
         
     | 
| 
       711 
     | 
    
         
            -
                  end
         
     | 
| 
       712 
     | 
    
         
            -
             
     | 
| 
       713 
     | 
    
         
            -
                  def next_temp_value
         
     | 
| 
       714 
     | 
    
         
            -
                    @temps += 1
         
     | 
| 
       715 
     | 
    
         
            -
                  end
         
     | 
| 
       716 
     | 
    
         
            -
             
     | 
| 
       717 
     | 
    
         
            -
                  def auto_use_temp_node?(code)
         
     | 
| 
       718 
     | 
    
         
            -
                    code.scan(CUR_PLACEHOLDER).count > 1
         
     | 
| 
       719 
     | 
    
         
            -
                  end
         
     | 
| 
       720 
     | 
    
         
            -
             
     | 
| 
       721 
     | 
    
         
            -
                  # with_<...>_context methods are used whenever the context,
         
     | 
| 
       722 
     | 
    
         
            -
                  # i.e the current node or the current element can be determined.
         
     | 
| 
       723 
     | 
    
         
            -
             
     | 
| 
       724 
     | 
    
         
            -
                  def with_child_context(code, child_index)
         
     | 
| 
       725 
     | 
    
         
            -
                    with_context(code, "#{CUR_NODE}.children[#{child_index}]")
         
     | 
| 
       726 
     | 
    
         
            -
                  end
         
     | 
| 
       727 
     | 
    
         
            -
             
     | 
| 
       728 
     | 
    
         
            -
                  def with_context(code, cur_node,
         
     | 
| 
       729 
     | 
    
         
            -
                                   use_temp_node: auto_use_temp_node?(code))
         
     | 
| 
       730 
     | 
    
         
            -
                    if use_temp_node
         
     | 
| 
       731 
     | 
    
         
            -
                      with_temp_node(cur_node) do |init, temp_var|
         
     | 
| 
       732 
     | 
    
         
            -
                        substitute_cur_node(code, temp_var, first_cur_node: init)
         
     | 
| 
       733 
     | 
    
         
            -
                      end
         
     | 
| 
       734 
     | 
    
         
            -
                    else
         
     | 
| 
       735 
     | 
    
         
            -
                      substitute_cur_node(code, cur_node)
         
     | 
| 
       736 
     | 
    
         
            -
                    end
         
     | 
| 
       737 
     | 
    
         
            -
                  end
         
     | 
| 
       738 
     | 
    
         
            -
             
     | 
| 
       739 
     | 
    
         
            -
                  def with_seq_head_context(code)
         
     | 
| 
       740 
     | 
    
         
            -
                    if code.include?(SEQ_HEAD_GUARD)
         
     | 
| 
       741 
     | 
    
         
            -
                      fail_due_to('parentheses at sequence head')
         
     | 
| 
       742 
     | 
    
         
            -
                    end
         
     | 
| 
       743 
     | 
    
         
            -
             
     | 
| 
       744 
     | 
    
         
            -
                    code.gsub CUR_ELEMENT, "#{CUR_NODE}.type"
         
     | 
| 
       745 
     | 
    
         
            -
                  end
         
     | 
| 
       746 
     | 
    
         
            -
             
     | 
| 
       747 
     | 
    
         
            -
                  def substitute_cur_node(code, cur_node, first_cur_node: cur_node)
         
     | 
| 
       748 
     | 
    
         
            -
                    iter = 0
         
     | 
| 
       749 
     | 
    
         
            -
                    code
         
     | 
| 
       750 
     | 
    
         
            -
                      .gsub(CUR_ELEMENT, CUR_NODE)
         
     | 
| 
       751 
     | 
    
         
            -
                      .gsub(CUR_NODE) do
         
     | 
| 
       752 
     | 
    
         
            -
                        iter += 1
         
     | 
| 
       753 
     | 
    
         
            -
                        iter == 1 ? first_cur_node : cur_node
         
     | 
| 
       754 
     | 
    
         
            -
                      end
         
     | 
| 
       755 
     | 
    
         
            -
                      .gsub(SEQ_HEAD_GUARD, '')
         
     | 
| 
       756 
     | 
    
         
            -
                  end
         
     | 
| 
       757 
     | 
    
         
            -
             
     | 
| 
       758 
     | 
    
         
            -
                  def self.tokens(pattern)
         
     | 
| 
       759 
     | 
    
         
            -
                    pattern.scan(TOKEN).reject { |token| token =~ /\A#{SEPARATORS}\Z/ }
         
     | 
| 
       760 
     | 
    
         
            -
                  end
         
     | 
| 
       761 
     | 
    
         
            -
                end
         
     | 
| 
       762 
     | 
    
         
            -
                private_constant :Compiler
         
     | 
| 
       763 
     | 
    
         
            -
             
     | 
| 
       764 
     | 
    
         
            -
                # Helpers for defining methods based on a pattern string
         
     | 
| 
       765 
     | 
    
         
            -
                module Macros
         
     | 
| 
       766 
     | 
    
         
            -
                  # Define a method which applies a pattern to an AST node
         
     | 
| 
       767 
     | 
    
         
            -
                  #
         
     | 
| 
       768 
     | 
    
         
            -
                  # The new method will return nil if the node does not match
         
     | 
| 
       769 
     | 
    
         
            -
                  # If the node matches, and a block is provided, the new method will
         
     | 
| 
       770 
     | 
    
         
            -
                  # yield to the block (passing any captures as block arguments).
         
     | 
| 
       771 
     | 
    
         
            -
                  # If the node matches, and no block is provided, the new method will
         
     | 
| 
       772 
     | 
    
         
            -
                  # return the captures, or `true` if there were none.
         
     | 
| 
       773 
     | 
    
         
            -
                  def def_node_matcher(method_name, pattern_str)
         
     | 
| 
       774 
     | 
    
         
            -
                    compiler = Compiler.new(pattern_str, 'node')
         
     | 
| 
       775 
     | 
    
         
            -
                    src = "def #{method_name}(node = self" \
         
     | 
| 
       776 
     | 
    
         
            -
                          "#{compiler.emit_trailing_params});" \
         
     | 
| 
       777 
     | 
    
         
            -
                          "#{compiler.emit_method_code};end"
         
     | 
| 
       778 
     | 
    
         
            -
             
     | 
| 
       779 
     | 
    
         
            -
                    location = caller_locations(1, 1).first
         
     | 
| 
       780 
     | 
    
         
            -
                    class_eval(src, location.path, location.lineno)
         
     | 
| 
       781 
     | 
    
         
            -
                  end
         
     | 
| 
       782 
     | 
    
         
            -
             
     | 
| 
       783 
     | 
    
         
            -
                  # Define a method which recurses over the descendants of an AST node,
         
     | 
| 
       784 
     | 
    
         
            -
                  # checking whether any of them match the provided pattern
         
     | 
| 
       785 
     | 
    
         
            -
                  #
         
     | 
| 
       786 
     | 
    
         
            -
                  # If the method name ends with '?', the new method will return `true`
         
     | 
| 
       787 
     | 
    
         
            -
                  # as soon as it finds a descendant which matches. Otherwise, it will
         
     | 
| 
       788 
     | 
    
         
            -
                  # yield all descendants which match.
         
     | 
| 
       789 
     | 
    
         
            -
                  def def_node_search(method_name, pattern_str)
         
     | 
| 
       790 
     | 
    
         
            -
                    compiler = Compiler.new(pattern_str, 'node')
         
     | 
| 
       791 
     | 
    
         
            -
                    called_from = caller(1..1).first.split(':')
         
     | 
| 
       792 
     | 
    
         
            -
             
     | 
| 
       793 
     | 
    
         
            -
                    if method_name.to_s.end_with?('?')
         
     | 
| 
       794 
     | 
    
         
            -
                      node_search_first(method_name, compiler, called_from)
         
     | 
| 
       795 
     | 
    
         
            -
                    else
         
     | 
| 
       796 
     | 
    
         
            -
                      node_search_all(method_name, compiler, called_from)
         
     | 
| 
       797 
     | 
    
         
            -
                    end
         
     | 
| 
       798 
     | 
    
         
            -
                  end
         
     | 
| 
       799 
     | 
    
         
            -
             
     | 
| 
       800 
     | 
    
         
            -
                  def node_search_first(method_name, compiler, called_from)
         
     | 
| 
       801 
     | 
    
         
            -
                    node_search(method_name, compiler, 'return true', '', called_from)
         
     | 
| 
       802 
     | 
    
         
            -
                  end
         
     | 
| 
       803 
     | 
    
         
            -
             
     | 
| 
       804 
     | 
    
         
            -
                  def node_search_all(method_name, compiler, called_from)
         
     | 
| 
       805 
     | 
    
         
            -
                    yield_code = compiler.emit_yield_capture('node')
         
     | 
| 
       806 
     | 
    
         
            -
                    prelude = "return enum_for(:#{method_name}, node0" \
         
     | 
| 
       807 
     | 
    
         
            -
                              "#{compiler.emit_trailing_params}) unless block_given?"
         
     | 
| 
       808 
     | 
    
         
            -
             
     | 
| 
       809 
     | 
    
         
            -
                    node_search(method_name, compiler, yield_code, prelude, called_from)
         
     | 
| 
       810 
     | 
    
         
            -
                  end
         
     | 
| 
       811 
     | 
    
         
            -
             
     | 
| 
       812 
     | 
    
         
            -
                  def node_search(method_name, compiler, on_match, prelude, called_from)
         
     | 
| 
       813 
     | 
    
         
            -
                    src = node_search_body(method_name, compiler.emit_trailing_params,
         
     | 
| 
       814 
     | 
    
         
            -
                                           prelude, compiler.match_code, on_match)
         
     | 
| 
       815 
     | 
    
         
            -
                    filename, lineno = *called_from
         
     | 
| 
       816 
     | 
    
         
            -
                    class_eval(src, filename, lineno.to_i)
         
     | 
| 
       817 
     | 
    
         
            -
                  end
         
     | 
| 
       818 
     | 
    
         
            -
             
     | 
| 
       819 
     | 
    
         
            -
                  def node_search_body(method_name, trailing_params, prelude, match_code,
         
     | 
| 
       820 
     | 
    
         
            -
                                       on_match)
         
     | 
| 
       821 
     | 
    
         
            -
                    <<~RUBY
         
     | 
| 
       822 
     | 
    
         
            -
                      def #{method_name}(node0#{trailing_params})
         
     | 
| 
       823 
     | 
    
         
            -
                        #{prelude}
         
     | 
| 
       824 
     | 
    
         
            -
                        node0.each_node do |node|
         
     | 
| 
       825 
     | 
    
         
            -
                          if #{match_code}
         
     | 
| 
       826 
     | 
    
         
            -
                            #{on_match}
         
     | 
| 
       827 
     | 
    
         
            -
                          end
         
     | 
| 
       828 
     | 
    
         
            -
                        end
         
     | 
| 
       829 
     | 
    
         
            -
                        nil
         
     | 
| 
       830 
     | 
    
         
            -
                      end
         
     | 
| 
       831 
     | 
    
         
            -
                    RUBY
         
     | 
| 
       832 
     | 
    
         
            -
                  end
         
     | 
| 
       833 
     | 
    
         
            -
                end
         
     | 
| 
       834 
     | 
    
         
            -
             
     | 
| 
       835 
     | 
    
         
            -
                attr_reader :pattern
         
     | 
| 
       836 
     | 
    
         
            -
             
     | 
| 
       837 
     | 
    
         
            -
                def initialize(str)
         
     | 
| 
       838 
     | 
    
         
            -
                  @pattern = str
         
     | 
| 
       839 
     | 
    
         
            -
                  compiler = Compiler.new(str)
         
     | 
| 
       840 
     | 
    
         
            -
                  src = "def match(node0#{compiler.emit_trailing_params});" \
         
     | 
| 
       841 
     | 
    
         
            -
                        "#{compiler.emit_method_code}end"
         
     | 
| 
       842 
     | 
    
         
            -
                  instance_eval(src, __FILE__, __LINE__ + 1)
         
     | 
| 
       843 
     | 
    
         
            -
                end
         
     | 
| 
       844 
     | 
    
         
            -
             
     | 
| 
       845 
     | 
    
         
            -
                def match(*args)
         
     | 
| 
       846 
     | 
    
         
            -
                  # If we're here, it's because the singleton method has not been defined,
         
     | 
| 
       847 
     | 
    
         
            -
                  # either because we've been dup'ed or serialized through YAML
         
     | 
| 
       848 
     | 
    
         
            -
                  initialize(pattern)
         
     | 
| 
       849 
     | 
    
         
            -
                  match(*args)
         
     | 
| 
       850 
     | 
    
         
            -
                end
         
     | 
| 
       851 
     | 
    
         
            -
             
     | 
| 
       852 
     | 
    
         
            -
                def marshal_load(pattern)
         
     | 
| 
       853 
     | 
    
         
            -
                  initialize pattern
         
     | 
| 
       854 
     | 
    
         
            -
                end
         
     | 
| 
       855 
     | 
    
         
            -
             
     | 
| 
       856 
     | 
    
         
            -
                def marshal_dump
         
     | 
| 
       857 
     | 
    
         
            -
                  pattern
         
     | 
| 
       858 
     | 
    
         
            -
                end
         
     | 
| 
       859 
     | 
    
         
            -
             
     | 
| 
       860 
     | 
    
         
            -
                def ==(other)
         
     | 
| 
       861 
     | 
    
         
            -
                  other.is_a?(NodePattern) &&
         
     | 
| 
       862 
     | 
    
         
            -
                    Compiler.tokens(other.pattern) == Compiler.tokens(pattern)
         
     | 
| 
       863 
     | 
    
         
            -
                end
         
     | 
| 
       864 
     | 
    
         
            -
                alias eql? ==
         
     | 
| 
       865 
     | 
    
         
            -
             
     | 
| 
       866 
     | 
    
         
            -
                def to_s
         
     | 
| 
       867 
     | 
    
         
            -
                  "#<#{self.class} #{pattern}>"
         
     | 
| 
       868 
     | 
    
         
            -
                end
         
     | 
| 
       869 
     | 
    
         
            -
             
     | 
| 
       870 
     | 
    
         
            -
                # Yields its argument and any descendants, depth-first.
         
     | 
| 
       871 
     | 
    
         
            -
                #
         
     | 
| 
       872 
     | 
    
         
            -
                def self.descend(element, &block)
         
     | 
| 
       873 
     | 
    
         
            -
                  return to_enum(__method__, element) unless block_given?
         
     | 
| 
       874 
     | 
    
         
            -
             
     | 
| 
       875 
     | 
    
         
            -
                  yield element
         
     | 
| 
       876 
     | 
    
         
            -
             
     | 
| 
       877 
     | 
    
         
            -
                  if element.is_a?(::RuboCop::AST::Node)
         
     | 
| 
       878 
     | 
    
         
            -
                    element.children.each do |child|
         
     | 
| 
       879 
     | 
    
         
            -
                      descend(child, &block)
         
     | 
| 
       880 
     | 
    
         
            -
                    end
         
     | 
| 
       881 
     | 
    
         
            -
                  end
         
     | 
| 
       882 
     | 
    
         
            -
             
     | 
| 
       883 
     | 
    
         
            -
                  nil
         
     | 
| 
       884 
     | 
    
         
            -
                end
         
     | 
| 
       885 
     | 
    
         
            -
              end
         
     | 
| 
       886 
     | 
    
         
            -
            end
         
     | 
| 
       887 
     | 
    
         
            -
            # rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity
         
     |