docs: def match(self, expr) -> MatchDict:
          """Match the given expression (recursively)
  
          Returns a :class:`MatchDict` instance that maps any wildcard names to
          the expressions that the corresponding wildcard pattern matches. For
          (sub-)pattern that have a `mode` attribute other than `Pattern.single`,
          the wildcard name is mapped to a list of all matched expression.
  
          If the match is successful, the resulting :class:`MatchDict` instance
          will evaluate to True in a boolean context. If the match is not
          successful, it will evaluate as False, and the reason for failure is
          available in the `reason` attribute of the :class:`MatchDict` object.
          """
          res = MatchDict()
          if self._has_non_single_arg:
              if self._non_single_arg_on_left:
                  res.merge_lists = 1
              else:
                  res.merge_lists = -1
          if self.head is not None:
              if not isinstance(expr, self.head):
                  res.reason = ("%s is not an instance of %s"
                                % (repr(expr), self._repr_head()))
                  res.success = False
                  return res
          for i_cond, condition in enumerate(self.conditions):
              if not condition(expr):
                  res.reason = ("%s does not meet condition %d"
                                % (repr(expr), i_cond+1))
                  res.success = False
                  return res
          try:
              if self.args is not None:
                  arg_pattern = self.extended_arg_patterns()
                  for arg in self._arg_iterator(expr.args):
                      current_arg_pattern = next(arg_pattern)
                      res.update(match_pattern(current_arg_pattern, arg))
                      if not res.success:
                          return res
                  # ensure that we have matched all arg patterns
                  try:
                      last_arg_pattern = next(arg_pattern)
                      res.update(self._check_last_arg_pattern(
                                      current_arg_pattern, last_arg_pattern))
                  except StopIteration:
                      pass  # expected, if current_arg_pattern was the last one
              if self.kwargs is not None:
                  for key, arg_pattern in self.kwargs.items():
                      res.update(match_pattern(arg_pattern, expr.kwargs[key]))
                      if not res.success:
                          return res
          except AttributeError as exc_info:
              res.reason = ("%s is a scalar, not an Expression: %s"
                            % (repr(expr), str(exc_info)))
              res.success = False
          except ValueError as exc_info:
              res.reason = "%s: %s" % (repr(expr), str(exc_info))
              res.success = False
          except StopIteration:
              res.reason = ("%s has an too many positional arguments"
                            % repr(expr))
              res.success = False
          except KeyError as exc_info:
              if "has already been set" in str(exc_info):
                  res.reason = "Double wildcard: %s" % str(exc_info)
              else:
                  res.reason = ("%s has no keyword argument %s"
                                % (repr(expr), str(exc_info)))
              res.success = False
          if res.success:
              if self.wc_name is not None:
                  try:
                      if self.mode > self.single:
                          res[self.wc_name] = [expr, ]
                      else:
                          res[self.wc_name] = expr
                  except KeyError as exc_info:
                      res.reason = "Double wildcard: %s" % str(exc_info)
                      res.success = False
          return res