def _parse_expression(s):
<EOL>operators = {<EOL>'<STR_LIT>': And,<EOL>'<STR_LIT>': Or,<EOL>None: lambda *args: args[<NUM_LIT:0>]<EOL>}<EOL>group_pairs = {<EOL>'<STR_LIT:)>': '<STR_LIT:(>',<EOL>'<STR_LIT:]>': '<STR_LIT:[>'<EOL>}<EOL>scanner = re.compile(r'''<STR_LIT>''', re.DOTALL | re.VERBOSE | re.UNICODE | re.IGNORECASE)<EOL>expect_operator = False<EOL>clause_stack = []<EOL>current_clause = []<EOL>clause_operator = None<EOL>clause_symbol = None<EOL>def close():<EOL><INDENT>prev_op, prev_symbol, prev_clause = clause_stack.pop()<EOL>prev_clause.append(operators[clause_operator](*current_clause))<EOL>return prev_op, prev_symbol, prev_clause<EOL><DEDENT>for match in re.finditer(scanner, s):<EOL><INDENT>(space, group_start, group_end, operator, variable, end,<EOL>error) = match.groups()<EOL>if error is not None:<EOL><INDENT>raise ParseError('<STR_LIT>'.format(<EOL>repr(match.group(<NUM_LIT:0>))), span=(match.start(), match.end()))<EOL><DEDENT>elif space is not None:<EOL><INDENT>continue<EOL><DEDENT>elif expect_operator and operator is not None:<EOL><INDENT>operator = operator.lower()<EOL>if operator == '<STR_LIT>' and clause_operator != '<STR_LIT>':<EOL><INDENT>prev_term = current_clause.pop()<EOL>clause_stack.append(<EOL>(clause_operator, clause_symbol, current_clause))<EOL>current_clause = [prev_term]<EOL><DEDENT>elif operator == '<STR_LIT>' and clause_operator == '<STR_LIT>':<EOL><INDENT>clause_operator, clause_symbol, current_clause = close()<EOL><DEDENT>clause_operator = operator<EOL>expect_operator = False<EOL><DEDENT>elif expect_operator and group_end is not None:<EOL><INDENT>if clause_operator == '<STR_LIT>':<EOL><INDENT>clause_operator, clause_symbol, current_clause = close()<EOL><DEDENT>if len(clause_stack) == <NUM_LIT:0>:<EOL><INDENT>raise ParseError(<EOL>'<STR_LIT>',<EOL>span=(match.start(), match.end()))<EOL><DEDENT>if group_pairs[group_end] != clause_symbol:<EOL><INDENT>raise ParseError(<EOL>'<STR_LIT>'.format(<EOL>clause_symbol, group_end),<EOL>span=(match.start(), match.end()))<EOL><DEDENT>clause_operator, clause_symbol, current_clause = close()<EOL><DEDENT>elif expect_operator and end is not None:<EOL><INDENT>if clause_operator == '<STR_LIT>':<EOL><INDENT>clause_operator, clause_symbol, current_clause = close()<EOL><DEDENT><DEDENT>elif not expect_operator and variable is not None:<EOL><INDENT>current_clause.append(Variable(variable))<EOL>expect_operator = True<EOL><DEDENT>elif not expect_operator and group_start is not None:<EOL><INDENT>clause_stack.append(<EOL>(clause_operator, clause_symbol, current_clause))<EOL>current_clause = []<EOL>clause_operator = None<EOL>clause_symbol = group_start<EOL><DEDENT>else:<EOL><INDENT>raise ParseError(<EOL>'<STR_LIT>'.format(<EOL>match.group(<NUM_LIT:0>)),<EOL>span=(match.start(), match.end()))<EOL><DEDENT><DEDENT>if len(clause_stack) > <NUM_LIT:0>:<EOL><INDENT>raise ParseError('<STR_LIT>')<EOL><DEDENT>expr = operators[clause_operator](*current_clause)<EOL>return expr<EOL>
Parse boolean expression containing and/or operators