def METHOD_NAME(self, node):
    if isinstance(node, py_ast.BoolOp):
        # is AND or OR
        op = node.op.__class__.__name__
        # values can be more than 2
        arg1 = self.METHOD_NAME(node.values[0])
        for val1 in node.values[1:]:
            arg2 = self.METHOD_NAME(val1)
            arg1 = BinaryOperation(op=op, args=[arg1, arg2])
        return arg1
    if isinstance(node, py_ast.Compare):
        # it is
        if len(node.ops) != 1:
            raise NotImplementedError(f'Multiple ops {node.ops}')
        op = self.compare_op(node.ops[0])
        arg1 = self.METHOD_NAME(node.left)
        arg2 = self.METHOD_NAME(node.comparators[0])
        return BinaryOperation(op=op, args=[arg1, arg2])
    if isinstance(node, py_ast.Name):
        # is special operator: latest, ...
        if node.id == 'latest':
            return Latest()
    if isinstance(node, py_ast.Constant):
        # it is constant
        return Constant(value=node.value)
    # ---- python 3.7 objects -----
    if isinstance(node, py_ast.Str):
        return Constant(value=node.s)
    if isinstance(node, py_ast.Num):
        return Constant(value=node.n)
    # -----------------------------
    if isinstance(node, py_ast.Attribute):
        # is 'this.field' - is attribute
        if node.value.id != 'this':
            raise NotImplementedError(f'Unknown variable {node.value.id}')
        return Identifier(parts=[node.attr])
    raise NotImplementedError(f'Unknown node {node}')