# Trying again


class Expression:
    def __add__(self, other):
        if isinstance(other, int) or isinstance(other, float):
            other = Constant(other)
        return Addition(self, other)


class Constant(Expression):
    def __init__(self, val):
        if isinstance(val, int) or isinstance(val, float):
            self.val = val
        else:
            raise TypeError

    def __str__(self):
        return f"{self.val}"

    def __eq__(self, other):
        if isinstance(other, Constant):
            return self.val == other.val
        return False

    def evaluate(self, env):
        return self.val

    def derivative(self, name):
        return Constant(0)

    def simplify(self):
        return self

    def decompose(self):
        return []


class Variable(Expression):
    def __init__(self, name):
        if name[0].isalpha() and name[0].isascii():
            self.name = name
        else:
            raise TypeError

    def __str__(self):
        return f"{self.name}"

    def __eq__(self, other):
        if isinstance(other, Variable):
            return self.name == other.name
        return False

    # def __neg__(self):
    #     pass

    def evaluate(self, env):
        return Constant(env[self.name]).evaluate(env)

    def derivative(self, name):
        return Constant(1 if self.name == name else 0)

    def decompose(self):
        return [self.name]


class UnaryOp(Expression):
    pass


class BinaryOp(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right
        self.name = ""

    def __str__(self):
        return f"({self.left} {self.name} {self.right})"

    def evaluate(self, env):
        return self.operate(self.left.evaluate(env), self.right.evaluate(env))

    def decompose(self):
        return self.left.vs() + self.right.vs()


class Addition(BinaryOp):
    def __init__(self, left, right):
        super().__init__(left, right)
        self.name = "+"

    def operate(self, x, y):
        return x + y

    def derivative(self, name):
        return self.left.derivative(name) + self.right.derivative(name)

    def simplify(self):
        left = self.left.simplify()
        right = self.right.simplify()
        if left.decompose() == []:
            left = left.evaluate({})
        if right.decompose() == []:
            right = right.evaluate({})

        if isinstance(left, Constant) and isinstance(right, Constant):
            return Constant(left.val + right.val)

        if left == Constant(0):
            return right

        if right == Constant(0):
            return left

        return left + right