def METHOD_NAME(acl_formula):
  """
  Parse an ACL formula expression into a parse tree that we can interpret in JS, e.g.
  "rec.office == 'Seattle' and user.email in ['sally@', 'xie@']".
  The idea is to support enough to express ACL rules flexibly, but we don't need to support too
  much, since rules should be reasonably simple.
  The returned tree has the form [NODE_TYPE, arguments...], with these NODE_TYPEs supported:
    And|Or                  ...values
    Add|Sub|Mult|Div|Mod    left, right
    Not                     operand
    Eq|NotEq|Lt|LtE|Gt|GtE  left, right
    Is|IsNot|In|NotIn       left, right
    List                    ...elements
    Const                   value (number, string, bool)
    Name                    name (string)
    Attr                    node, attr_name
    Comment                 node, comment
  """
  if isinstance(acl_formula, six.binary_type):
    acl_formula = acl_formula.decode('utf8')
  try:
    acl_formula = replace_dollar_attrs(acl_formula)
    tree = ast.parse(acl_formula, mode='eval')
    result = _TreeConverter().visit(tree)
    for part in tokenize.generate_tokens(io.StringIO(acl_formula).readline):
      if part[0] == tokenize.COMMENT and part[1].startswith('#'):
        result = ['Comment', result, part[1][1:].strip()]
        break
    return result
  except SyntaxError as err:
    # In case of an error, include line and offset.
    raise SyntaxError("%s on line %s col %s" % (err.args[0], err.lineno, err.offset))