Return a Node that is the root of the parse tree for the the specified
        expression.

        :param exp: A list that represents a relational algebra expression.
        Assumes that this list was generated by pyparsing.
        :param schema: A dictionary of relation names to attribute names used
        for verification and generating attributes.
        :return: A Node.

def to_node(self, exp, schema):
        """
        Return a Node that is the root of the parse tree for the the specified
        expression.

        :param exp: A list that represents a relational algebra expression.
        Assumes that this list was generated by pyparsing.
        :param schema: A dictionary of relation names to attribute names used
        for verification and generating attributes.
        :return: A Node.
        """
        # A relation node.
        if len(exp) == 1 and isinstance(exp[0], str):
            node = RelationNode(name=exp[0], schema=schema)

        # An expression.
        elif len(exp) == 1 and isinstance(exp[0], list):
            node = self.to_node(exp[0], schema)

        # Unary operators.
        elif isinstance(exp[0], str) and self.grammar.is_unary(exp[0]):
            child = self.to_node(exp[2:], schema)
            node = self.create_unary_node(operator=exp[0], child=child,
                                          param=exp[1], schema=schema)

        # Assignment.
        elif exp[1] is self.grammar.syntax.assign_op:
            child = self.to_node(exp[2:], schema)
            node = self.create_unary_node(operator=exp[1], child=child,
                                          param=exp[0], schema=schema)

        # Binary operators.
        elif self.grammar.is_binary(exp[1]):
            # Pyparsing will put different operators with the same precedence
            # in the same list. This can be a problem when we mix operators with
            # and without parameters (for example join). We avoid this below
            # and build from right to left, to create the correct syntax tree.
            if isinstance(exp[-2], str):
                # Operator without parameters
                op_pos = -2
                param = None
            else:
                op_pos = -3
                param = exp[-2]

            operator = exp[op_pos]
            left = self.to_node(exp[:op_pos], schema)
            right = self.to_node(exp[-1], schema)
            node = self.create_binary_node(operator=operator, left=left,
                                           right=right, param=param)

        else:
            raise ValueError

        return node