docs: def _parse_expression(s):
      """Parse boolean expression containing and/or operators"""
  
      # Converters for opeartor clauses
      operators = {
          'and': And,
          'or': Or,
          None: lambda *args: args[0]
      }
  
      # Pairing of end group symbols with start group symbols
      group_pairs = {
          ')': '(',
          ']': '['
      }
  
      scanner = re.compile(r'''
          (\s+) |              # space
          (\(|\[) |            # group_start
          (\)|\]) |            # group_end
          ((?:or|and)\b) |     # operator
          ([^\s\(\)\[\]]+) |   # variable
          (\Z) |               # end
          (.)                  # error
      ''', re.DOTALL | re.VERBOSE | re.UNICODE | re.IGNORECASE)
  
      # Parsed using two states and a stack of open clauses
      # At state 0 (not expect_operator): Expect variable, or parenthesis group
      #  start.
      # At state 1 (expect_operator): Expect operator, parenthesis group end, or
      #  end.
      expect_operator = False
      clause_stack = []
      current_clause = []
      clause_operator = None
      clause_symbol = None
  
      def close():
          prev_op, prev_symbol, prev_clause = clause_stack.pop()
          prev_clause.append(operators[clause_operator](*current_clause))
          return prev_op, prev_symbol, prev_clause
  
      for match in re.finditer(scanner, s):
          (space, group_start, group_end, operator, variable, end,
              error) = match.groups()
  
          if error is not None:
              raise ParseError('Invalid token in expression string: {}'.format(
                  repr(match.group(0))), span=(match.start(), match.end()))
          elif space is not None:
              continue
          elif expect_operator and operator is not None:
              operator = operator.lower()
              if operator == 'and' and clause_operator != 'and':
                  prev_term = current_clause.pop()
                  clause_stack.append(
                      (clause_operator, clause_symbol, current_clause))
                  current_clause = [prev_term]
              elif operator == 'or' and clause_operator == 'and':
                  clause_operator, clause_symbol, current_clause = close()
              clause_operator = operator
              expect_operator = False
          elif expect_operator and group_end is not None:
              if clause_operator == 'and':
                  clause_operator, clause_symbol, current_clause = close()
              if len(clause_stack) == 0:
                  raise ParseError(
                      'Unbalanced parenthesis group in expression',
                      span=(match.start(), match.end()))
              if group_pairs[group_end] != clause_symbol:
                  raise ParseError(
                      'Group started with {} ended with {}'.format(
                          clause_symbol, group_end),
                      span=(match.start(), match.end()))
              clause_operator, clause_symbol, current_clause = close()
          elif expect_operator and end is not None:
              if clause_operator == 'and':
                  clause_operator, clause_symbol, current_clause = close()
          elif not expect_operator and variable is not None:
              current_clause.append(Variable(variable))
              expect_operator = True
          elif not expect_operator and group_start is not None:
              clause_stack.append(
                  (clause_operator, clause_symbol, current_clause))
              current_clause = []
              clause_operator = None
              clause_symbol = group_start
          else:
              raise ParseError(
                  'Invalid token in expression string: {!r}'.format(
                      match.group(0)),
                  span=(match.start(), match.end()))
  
      if len(clause_stack) > 0:
          raise ParseError('Unbalanced parenthesis group in expression')
  
      expr = operators[clause_operator](*current_clause)
      return expr