class NuSMVParsingError(PyNuSMVError):

    """
    A :class:`NuSMVParsingError` is a NuSMV parsing exception. Contains several
    errors accessible through the :attr:`errors` attribute.

    """

    def __init__(self, errors):
        """
        Initialize this exception with errors.

        :param errors: a tuple of errors
        :type errors: tuple(:class:`Error`)
        """
        super(NuSMVParsingError, self).__init__(self)
        self._errors = errors

    @staticmethod
    def from_nusmv_errors_list(errors):
        """
        Create a new NuSMVParsingError from the given list of NuSMV errors.

        :param errors: the list of errors from NuSMV
        """
        errlist = []
        while errors is not None:
            error = nsnode.car(errors)
            err = nsparser.Parser_get_syntax_error(error)
            errlist.append(_Error(*err[1:]))
            errors = nsnode.cdr(errors)
        return NuSMVParsingError(tuple(errlist))

    def __str__(self):
        return "\n".join([str(err) for err in self._errors])

    def __repr__(self):
        return repr(self._errors)

    @property
    def errors(self):
        """
        The tuple of errors of this exception. These errors are tuples
        `(line, token, message)` representing the line, the token and the
        message of the error.

        """
        return self._errors def update(old, new):
    """
    Update `old` with `new`. `old` is assumed to have the `extend` or `update`
    method, and `new` is assumed to be a good argument for the corresponding
    method.

    :param old: the data to update.
    :param new: the date to update with.

    """
    try:
        old.extend(new)
    except AttributeError:
        old.update(new) class Identifier(Expression):

    """An identifier."""

    def __init__(self, name, *args, **kwargs):
        super(Identifier, self).__init__(*args, **kwargs)
        self.name = name

    def __str__(self):
        string = str(self.name)
        return super(Identifier, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.name == other.name
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Identifier") + 23 ** 2 * hash(self.name)

    def __deepcopy__(self, memo):
        return Identifier(self.name) class Self(Identifier):

    """The `self` identifier."""

    def __init__(self, *args, **kwargs):
        super(Self, self).__init__("self", *args, **kwargs) class Dot(ComplexIdentifier):

    """Access to a part of a module instance."""

    def __init__(self, instance, element, *args, **kwargs):
        super(Dot, self).__init__(*args, **kwargs)
        self.instance = instance
        self.element = element

    def __str__(self):
        string = str(self.instance) + "." + str(self.element)
        return super(Dot, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.instance._equals(other.instance) and
                    self.element._equals(other.element))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Dot") + 23 ** 2 * hash(self.instance) +
                23 ** 3 * hash(self.element))

    def __deepcopy__(self, memo):
        return Dot(deepcopy(self.instance, memo),
                   deepcopy(self.element, memo)) class ArrayAccess(ComplexIdentifier):

    """Access to an index of an array."""

    def __init__(self, array, index, *args, **kwargs):
        super(ArrayAccess, self).__init__(*args, **kwargs)
        self.array = array
        self.index = index

    def __str__(self):
        string = str(self.array) + "[" + str(self.index) + "]"
        return super(ArrayAccess, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.array._equals(other.array) and
                    self.index._equals(other.index))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("ArrayAccess") + 23 ** 2 * hash(self.array) +
                23 ** 3 * hash(self.index))

    def __deepcopy__(self, memo):
        return ArrayAccess(deepcopy(self.array, memo),
                           deepcopy(self.index, memo)) class Trueexp(BooleanConst):

    """The TRUE constant."""

    def __init__(self, *args, **kwargs):
        super(Trueexp, self).__init__("TRUE", *args, **kwargs)

    def __deepcopy__(self, memo):
        return Trueexp() class Falseexp(BooleanConst):

    """The FALSE constant."""

    def __init__(self, *args, **kwargs):
        super(Falseexp, self).__init__("FALSE", *args, **kwargs)

    def __deepcopy__(self, memo):
        return Falseexp() class NumericalConst(Constant):

    """A numerical constant."""

    def __init__(self, value, *args, **kwargs):
        super(NumericalConst, self).__init__(*args, **kwargs)
        self.value = str(value)

    def __str__(self):
        string = self.value
        return super(NumericalConst, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value == other.value
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("NumericalConst") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return NumericalConst(deepcopy(self.value, memo)) class NumberWord(Constant):

    """A word constant."""

    def __init__(self, value, *args, **kwargs):
        super(NumberWord, self).__init__(*args, **kwargs)
        self.value = value

    def __str__(self):
        string = str(self.value)
        return super(NumberWord, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value == other.value
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Word") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return NumberWord(deepcopy(self.value, memo)) class RangeConst(Constant):

    """A range of integers."""

    def __init__(self, start, stop, *args, **kwargs):
        super(RangeConst, self).__init__(*args, **kwargs)
        self.start = start
        self.stop = stop

    def __str__(self):
        string = str(self.start) + " .. " + str(self.stop)
        return super(RangeConst, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.start == other.start and self.stop == other.stop
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("RangeConst")
                + 23 ** 2 * hash(self.start) + 23 ** 3 * hash(self.stop))

    def __deepcopy__(self, memo):
        return RangeConst(deepcopy(self.start, memo),
                          deepcopy(self.stop, memo)) class Conversion(Function):

    """Converting an expression into a specific type."""

    def __init__(self, target_type, value, *args, **kwargs):
        super(Conversion, self).__init__(*args, **kwargs)
        self.target_type = target_type
        self.value = value

    def __str__(self):
        string = str(self.target_type) + "(" + str(self.value) + ")"
        return super(Conversion, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.target_type == other.target_type and
                    self.value._equals(other.value))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Conversion")
                + 23 ** 2 * hash(self.target_type)
                + 23 ** 3 * hash(self.value))

    def __deepcopy__(self, memo):
        return Conversion(deepcopy(self.target_type, memo),
                          deepcopy(self.value, memo)) class WordFunction(Function):

    """A function applied on a word."""

    def __init__(self, function, value, size, *args, **kwargs):
        super(WordFunction, self).__init__(*args, **kwargs)
        self.function = function
        self.value = value
        self.size = size

    def __str__(self):
        string = (str(self.function) +
                  "(" + str(self.value) +
                  ", " +
                  str(self.size) +
                  ")")
        return super(WordFunction, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.function == other.function and
                    self.value._equals(other.value) and
                    self.size._equals(other.size))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("WordFunction")
                + 23 ** 2 * hash(self.function)
                + 23 ** 3 * hash(self.value)
                + 23 ** 4 * hash(self.size))

    def __deepcopy__(self, memo):
        return WordFunction(deepcopy(self.function, memo),
                            deepcopy(self.value, memo),
                            deepcopy(self.size, memo)) class Count(Function):

    """A counting function."""

    def __init__(self, values, *args, **kwargs):
        super(Count, self).__init__(*args, **kwargs)
        self.values = values

    def __str__(self):
        string = ("count((" +
                  "), (".join(str(value) for value in self.values) +
                  "))")
        return super(Count, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            if len(self.values) != len(other.values):
                return False
            for sval, oval in zip(self.values, other.values):
                if not sval._equals(oval):
                    return False
            return True
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Count") + 23 ** 2 * hash(self.values)

    def __deepcopy__(self, memo):
        return Count(deepcopy(self.values, memo)) class Next(Expression):

    """A next expression."""

    def __init__(self, value, *args, **kwargs):
        super(Next, self).__init__(*args, **kwargs)
        self.value = value

    def __str__(self):
        string = "next(" + str(self.value) + ")"
        return super(Next, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value._equals(other.value)
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Next") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return Next(deepcopy(self.value, memo)) class Smallinit(Expression):

    """An init() expression."""

    def __init__(self, value, *args, **kwargs):
        super(Smallinit, self).__init__(*args, **kwargs)
        self.value = value

    def __str__(self):
        string = "init(" + str(self.value) + ")"
        return super(Smallinit, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value._equals(other.value)
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Smallinit") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return Smallinit(deepcopy(self.value, memo)) class Case(Expression):

    """A case expression."""

    def __init__(self, values, *args, **kwargs):
        super(Case, self).__init__(*args, **kwargs)
        self.values = values

    def __str__(self):
        string = ["\ncase"]
        for cond, body in OrderedDict(self.values).items():
            comments = []
            if hasattr(body, "comments") and body.comments:
                comments = body.comments
                body.comments = []

            current = str(cond) + ": " + str(body) + ";"
            string.append(_indent(
                          _add_comments_to_string(current, comments).strip()))

            if hasattr(body, "comments"):
                body.comments = comments
        string.append("esac")
        string = "\n".join(string)
        return super(Case, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.values == other.values
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Case") + 23 ** 2 * hash(self.values)

    def __deepcopy__(self, memo):
        return Case(deepcopy(self.values, memo)) class Subscript(Expression):

    """Array subscript."""

    def __init__(self, array, index, *args, **kwargs):
        super(Subscript, self).__init__(*args, **kwargs)
        self.array = array
        self.index = index

    def __str__(self):
        string = str(self.array) + "[" + str(self.index) + "]"
        return super(Subscript, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.array._equals(other.array) and
                    self.index == other.index)
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Subscript") +
                23 ** 2 * hash(self.array) +
                23 ** 3 * hash(self.index))

    def __deepcopy__(self, memo):
        return Subscript(deepcopy(self.array, memo),
                         deepcopy(self.index, memo)) class BitSelection(Expression):

    """Word bit selection."""

    def __init__(self, word, start, stop, *args, **kwargs):
        super(BitSelection, self).__init__(*args, **kwargs)
        self.word = word
        self.start = start
        self.stop = stop

    def __str__(self):
        string = (str(self.word) +
                 "[" +
                 str(self.start) +
                 ":" +
                 str(self.stop) +
                 "]")
        return super(BitSelection, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.word._equals(other.word) and
                    self.start._equals(other.start) and
                    self.stop._equals(other.stop))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("BitSelection")
                + 23 ** 2 * hash(self.word)
                + 23 ** 3 * hash(self.start)
                + 23 ** 4 * hash(self.stop))

    def __deepcopy__(self, memo):
        return BitSelection(deepcopy(self.word, memo),
                            deepcopy(self.start, memo),
                            deepcopy(self.stop, memo)) class Set(Expression):

    """A set."""

    def __init__(self, elements, *args, **kwargs):
        super(Set, self).__init__(*args, **kwargs)
        self.elements = elements

    def __str__(self):
        string = ("{" +
                  ", ".join(str(element) for element in self.elements) +
                  "}")
        return super(Set, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return frozenset(self.elements) == frozenset(other.elements)
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Set") + 23 ** 2 * hash(frozenset(self.elements))

    def __deepcopy__(self, memo):
        return Set(deepcopy(self.elements, memo)) class Not(Operator):

    """A negated (`-`) expression."""

    _precedence = 1

    def __init__(self, value, *args, **kwargs):
        super(Not, self).__init__(*args, **kwargs)
        self.value = value

    def __str__(self):
        string = "! " + self._enclose(self.value)
        return super(Not, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value._equals(other.value)
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Not") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return Not(deepcopy(self.value, memo)) class Concat(Operator):

    """A concatenation (`::`) of expressions."""

    _precedence = 2

    def __init__(self, left, right, *args, **kwargs):
        super(Concat, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " :: " + self._enclose(self.right)
        return super(Concat, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Concat") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Concat(deepcopy(self.left, memo),
                      deepcopy(self.right, memo)) class Minus(Operator):

    """Minus (`-`) expression."""

    _precedence = 3

    def __init__(self, value, *args, **kwargs):
        super(Minus, self).__init__(*args, **kwargs)
        self.value = value

    def __str__(self):
        string = "- " + self._enclose(self.value)
        return super(Minus, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return self.value._equals(other.value)
        else:
            return False

    def __hash__(self):
        return 17 + 23 * hash("Minus") + 23 ** 2 * hash(self.value)

    def __deepcopy__(self, memo):
        return Minus(deepcopy(self.value, memo)) class Mult(Operator):

    """A multiplication (`*`) of expressions."""

    _precedence = 4

    def __init__(self, left, right, *args, **kwargs):
        super(Mult, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " * " + self._enclose(self.right)
        return super(Mult, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Mult") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Mult(deepcopy(self.left, memo),
                    deepcopy(self.right, memo)) class Div(Operator):

    """A division (`/`) of expressions."""

    _precedence = 4

    def __init__(self, left, right, *args, **kwargs):
        super(Div, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " / " + self._enclose(self.right)
        return super(Div, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Div") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Div(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Mod(Operator):

    """A modulo (`%`) of expressions."""

    _precedence = 4

    def __init__(self, left, right, *args, **kwargs):
        super(Mod, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " mod " + self._enclose(self.right)
        return super(Mod, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Mod") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Mod(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Add(Operator):

    """An addition (`+`) of expressions."""

    _precedence = 5

    def __init__(self, left, right, *args, **kwargs):
        super(Add, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " + " + self._enclose(self.right)
        return super(Add, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Add") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Add(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Sub(Operator):

    """A subtraction (`-`) of expressions."""

    _precedence = 5

    def __init__(self, left, right, *args, **kwargs):
        super(Sub, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " - " + self._enclose(self.right)
        return super(Sub, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Sub") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Sub(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class LShift(Operator):

    """A left shift (`<<`) of expressions."""

    _precedence = 6

    def __init__(self, left, right, *args, **kwargs):
        super(LShift, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " << " + self._enclose(self.right)
        return super(LShift, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("LShift") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return LShift(deepcopy(self.left, memo),
                      deepcopy(self.right, memo)) class RShift(Operator):

    """A right shift (`>>`) of expressions."""

    _precedence = 6

    def __init__(self, left, right, *args, **kwargs):
        super(RShift, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " >> " + self._enclose(self.right)
        return super(RShift, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("RShift") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return RShift(deepcopy(self.left, memo),
                      deepcopy(self.right, memo)) class Union(Operator):

    """A union (`union`) of expressions."""

    _precedence = 7

    def __init__(self, left, right, *args, **kwargs):
        super(Union, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = (self._enclose(self.left) +
                  " union " +
                  self._enclose(self.right))
        return super(Union, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Union") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Union(deepcopy(self.left, memo),
                     deepcopy(self.right, memo)) class In(Operator):

    """The `in` expression."""

    _precedence = 8

    def __init__(self, left, right, *args, **kwargs):
        super(In, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " in " + self._enclose(self.right)
        return super(In, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("In") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return In(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class Equal(Operator):

    """The `=` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(Equal, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " = " + self._enclose(self.right)
        return super(Equal, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Equal") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __bool__(self):
        if (isinstance(self.left, Expression) and
                isinstance(self.right, Expression)):
            return self.left._equals(self.right)
        else:
            return self.left == self.right

    def __nonzero__(self):
        return self.__bool__()

    def __deepcopy__(self, memo):
        return Equal(deepcopy(self.left, memo),
                     deepcopy(self.right, memo)) class NotEqual(Operator):

    """The `!=` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(NotEqual, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " != " + self._enclose(self.right)
        return super(NotEqual, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((not self.left._equals(other.left) or
                     not self.right._equals(other.right)) and
                    (not self.left._equals(other.right) or
                     not self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("NotEqual") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __bool__(self):
        if (isinstance(self.left, Expression) and
                isinstance(self.right, Expression)):
            return not self.left._equals(self.right)
        else:
            return self.left != self.right

    def __nonzero__(self):
        return self.__bool__()

    def __deepcopy__(self, memo):
        return NotEqual(deepcopy(self.left, memo),
                        deepcopy(self.right, memo)) class Lt(Operator):

    """The `<` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(Lt, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " < " + self._enclose(self.right)
        return super(Lt, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Lt") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Lt(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class Gt(Operator):

    """The `>` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(Gt, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " > " + self._enclose(self.right)
        return super(Gt, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Gt") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Gt(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class Le(Operator):

    """The `<=` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(Le, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " <= " + self._enclose(self.right)
        return super(Le, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Le") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Le(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class Ge(Operator):

    """The `>=` expression."""

    _precedence = 9

    def __init__(self, left, right, *args, **kwargs):
        super(Ge, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " >= " + self._enclose(self.right)
        return super(Ge, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Ge") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Ge(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class And(Operator):

    """The `&` expression."""

    _precedence = 10

    def __init__(self, left, right, *args, **kwargs):
        super(And, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " & " + self._enclose(self.right)
        return super(And, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("And") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return And(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Or(Operator):

    """The `|` expression."""

    _precedence = 11

    def __init__(self, left, right, *args, **kwargs):
        super(Or, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " | " + self._enclose(self.right)
        return super(Or, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Or") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Or(deepcopy(self.left, memo),
                  deepcopy(self.right, memo)) class Xor(Operator):

    """The `xor` expression."""

    _precedence = 11

    def __init__(self, left, right, *args, **kwargs):
        super(Xor, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " xor " + self._enclose(self.right)
        return super(Xor, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Xor") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Xor(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Xnor(Operator):

    """The `xnor` expression."""

    _precedence = 11

    def __init__(self, left, right, *args, **kwargs):
        super(Xnor, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = (self._enclose(self.left) +
                  " xnor " +
                  self._enclose(self.right))
        return super(Xnor, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Xnor") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Xnor(deepcopy(self.left, memo),
                    deepcopy(self.right, memo)) class Ite(Operator):

    """The `? :` expression."""

    _precedence = 12

    def __init__(self, condition, left, right, *args, **kwargs):
        super(Ite, self).__init__(*args, **kwargs)
        self.condition = condition
        self.left = left
        self.right = right

    def __str__(self):
        string = (self._enclose(self.condition) +
                  " ? " +
                  self._enclose(self.left) +
                  " : " +
                  self._enclose(self.right))
        return super(Ite, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.condition._equals(other.condition) and
                    self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Ite") + 23 ** 2 * hash(self.condition)
                + 23 ** 3 * hash(self.left) + 23 ** 4 * hash(self.right))

    def __deepcopy__(self, memo):
        return Ite(deepcopy(self.condition, memo),
                   deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Iff(Operator):

    """The `<->` expression."""

    _precedence = 13

    def __init__(self, left, right, *args, **kwargs):
        super(Iff, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " <-> " + self._enclose(self.right)
        return super(Iff, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return ((self.left._equals(other.left) and
                     self.right._equals(other.right)) or
                    (self.left._equals(other.right) and
                     self.right._equals(other.left)))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Iff") + 23 ** 2 * hash(self.left)
                + 23 ** 2 * hash(self.right))

    def __deepcopy__(self, memo):
        return Iff(deepcopy(self.left, memo),
                   deepcopy(self.right, memo)) class Implies(Operator):

    """The `->` expression."""

    _precedence = 14

    def __init__(self, left, right, *args, **kwargs):
        super(Implies, self).__init__(*args, **kwargs)
        self.left = left
        self.right = right

    def __str__(self):
        string = self._enclose(self.left) + " -> " + self._enclose(self.right)
        return super(Implies, self)._to_string(string=string)

    def _equals(self, other):
        """Return whether `self` is equals to `other`."""
        if isinstance(self, type(other)):
            return (self.left._equals(other.left) and
                    self.right._equals(other.right))
        else:
            return False

    def __hash__(self):
        return (17 + 23 * hash("Implies") + 23 ** 2 * hash(self.left)
                + 23 ** 3 * hash(self.right))

    def __deepcopy__(self, memo):
        return Implies(deepcopy(self.left, memo),
                       deepcopy(self.right, memo)) class ArrayExpr(Element):

    """An array define expression."""

    def __init__(self, array, *args, **kwargs):
        super(ArrayExpr, self).__init__(*args, **kwargs)
        self.array = array

    def __str__(self):
        string = str(self.array)
        return super(ArrayExpr, self)._to_string(string=string)

    def __hash__(self):
        return 17 + 23 * hash("ArrayExpr") + 23 ** 2 * hash(self.array)

    def __deepcopy__(self, memo):
        return ArrayExpr(deepcopy(self.array, memo)) class Boolean(SimpleType):

    """A boolean type."""

    def __str__(self):
        string = "boolean"
        return super(Boolean, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Boolean() class Word(SimpleType):

    """A word type."""

    def __init__(self, size, sign=None, *args, **kwargs):
        super(Word, self).__init__(*args, **kwargs)
        self.size = size
        self.sign = sign

    def __str__(self):
        string = ((self.sign + " " if self.sign else "") +
                  "word" +"[" + str(self.size) + "]")
        return super(Word, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Word(deepcopy(self.size, memo),
                    deepcopy(self.sign, memo)) class Scalar(SimpleType):

    """An enumeration type."""

    def __init__(self, values, *args, **kwargs):
        super(Scalar, self).__init__(*args, **kwargs)
        self.values = values

    def __str__(self):
        string = "{" + ", ".join(str(value) for value in self.values) + "}"
        return super(Scalar, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Scalar(deepcopy(self.values, memo)) class Range(SimpleType):

    """A range type."""

    def __init__(self, start, stop, *args, **kwargs):
        super(Range, self).__init__(*args, **kwargs)
        self.start = start
        self.stop = stop

    def __str__(self):
        string = str(self.start) + " .. " + str(self.stop)
        return super(Range, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Range(deepcopy(self.start, memo),
                     deepcopy(self.stop, memo)) class Array(SimpleType):

    """An array type."""

    def __init__(self, start, stop, elementtype, *args, **kwargs):
        super(Array, self).__init__(*args, **kwargs)
        self.start = start
        self.stop = stop
        self.elementtype = elementtype

    def __str__(self):
        string = ("array " +
                  str(self.start) +
                  " .. " +
                  str(self.stop) +
                  " of " +
                  str(self.elementtype))
        return super(Array, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Array(deepcopy(self.start, memo),
                     deepcopy(self.stop, memo),
                     deepcopy(self.elementtype, memo)) class Modtype(Type):

    """A module instantiation."""

    def __init__(self, modulename, arguments, process=False, *args, **kwargs):
        super(Modtype, self).__init__(*args, **kwargs)
        self.process = process
        self.modulename = modulename
        self.args = arguments

    def __str__(self):
        string = (("process " if self.process else "") +
                  str(self.modulename) +
                  "(" +
                  ", ".join(str(arg) for arg in self.args) +
                  ")")
        return super(Modtype, self)._to_string(string=string)

    def __deepcopy__(self, memo):
        return Modtype(deepcopy(self.modulename, memo),
                       deepcopy(self.args, memo),
                       process=deepcopy(self.process, memo)) class Variables(MappingSection):

    """Declaring variables."""

    def __init__(self, variables, *args, **kwargs):
        super(Variables, self).__init__("VAR", variables, *args, **kwargs) class InputVariables(MappingSection):

    """Declaring input variables."""

    def __init__(self, ivariables, *args, **kwargs):
        super(InputVariables, self).__init__("IVAR",
                                             ivariables,
                                             *args,
                                             **kwargs) class FrozenVariables(MappingSection):

    """Declaring frozen variables."""

    def __init__(self, fvariables, *args, **kwargs):
        super(FrozenVariables, self).__init__("FROZENVAR",
                                              fvariables,
                                              *args,
                                              **kwargs) class Defines(MappingSection):

    """Declaring defines."""

    def __init__(self, defines, *args, **kwargs):
        super(Defines, self).__init__("DEFINE",
                                      defines,
                                      internal_separator=" := ",
                                      *args,
                                      **kwargs) class Assigns(MappingSection):

    """Declaring assigns."""

    def __init__(self, assigns, *args, **kwargs):
        super(Assigns, self).__init__("ASSIGN",
                                      assigns,
                                      internal_separator=" := ",
                                      *args,
                                      **kwargs) class Constants(ListingSection):

    """Declaring constants."""

    def __init__(self, constants, *args, **kwargs):
        super(Constants, self).__init__("CONSTANTS",
                                        constants,
                                        separator=", ",
                                        indentation="",
                                        *args,
                                        **kwargs) class Trans(ListingSection):

    """A TRANS section."""

    def __init__(self, body, *args, **kwargs):
        super(Trans, self).__init__("TRANS",
                                    body,
                                    separator="\nTRANS\n",
                                    *args,
                                    **kwargs) class Init(ListingSection):

    """An INIT section."""

    def __init__(self, body, *args, **kwargs):
        super(Init, self).__init__("INIT",
                                   body,
                                   separator="\nINIT\n",
                                   *args,
                                   **kwargs) class Invar(ListingSection):

    """An INVAR section."""

    def __init__(self, body, *args, **kwargs):
        super(Invar, self).__init__("INVAR",
                                    body,
                                    separator="\nINVAR\n",
                                    *args,
                                    **kwargs) class Fairness(ListingSection):

    """A FAIRNESS section."""

    def __init__(self, body, *args, **kwargs):
        super(Fairness, self).__init__("FAIRNESS",
                                       body,
                                       separator="\nFAIRNESS\n",
                                       *args,
                                       **kwargs) class Justice(ListingSection):

    """A Justice section."""

    def __init__(self, body, *args, **kwargs):
        super(Justice, self).__init__("JUSTICE",
                                      body,
                                      separator="\nJUSTICE\n",
                                      *args,
                                      **kwargs) class Compassion(ListingSection):

    """A COMPASSION section."""

    def __init__(self, body, *args, **kwargs):
        super(Compassion, self).__init__("COMPASSION",
                                         body,
                                         separator="\nCOMPASSION\n",
                                         *args,
                                         **kwargs) class Expression(Element):

    """A generic expression."""

    _precedence = 0

    def __init__(self, *args, **kwargs):
        super(Expression, self).__init__(*args, **kwargs)

    def __repr__(self):
        return str(self)

    def __lt__(self, other):
        return self.lt(other)

    def lt(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Lt(self, other)

    def __le__(self, other):
        return self.le(other)

    def le(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Le(self, other)

    def __eq__(self, other):
        return self.eq(other)

    def eq(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Equal(self, other)

    def __ne__(self, other):
        return self.ne(other)

    def ne(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return NotEqual(self, other)

    def __gt__(self, other):
        return self.gt(other)

    def gt(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Gt(self, other)

    def __ge__(self, other):
        return self.ge(other)

    def ge(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Ge(self, other)

    def __add__(self, other):
        return self.add(other)

    def add(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Add(self, other)

    def __sub__(self, other):
        return self.sub(other)

    def __rsub__(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Sub(other, self)

    def sub(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Sub(self, other)

    def __mul__(self, other):
        return self.mul(other)

    def mul(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Mult(self, other)

    def __truediv__(self, other):
        return self.div(other)

    def div(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Div(self, other)

    def __mod__(self, other):
        return self.mod(other)

    def mod(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Mod(self, other)

    def __lshift__(self, other):
        return self.lshift(other)

    def lshift(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return LShift(self, other)

    def __rshift__(self, other):
        return self.rshift(other)

    def rshift(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return RShift(self, other)

    def __and__(self, other):
        return self.and_(other)

    def and_(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return And(self, other)

    def __xor__(self, other):
        return self.xor(other)

    def xor(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Xor(self, other)

    def xnor(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Xnor(self, other)

    def __or__(self, other):
        return self.or_(other)

    def or_(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Or(self, other)

    def __neg__(self):
        return self.neg()

    def neg(self):
        return self.minus()

    def minus(self):
        return Minus(self)

    def __invert__(self):
        return self.invert()

    def invert(self):
        return self.not_()

    def not_(self):
        return Not(self)

    def __getitem__(self, key):
        from .parser import parseAllString, next_expression
        if isinstance(key, slice):
            start, stop = slice.start, slice.stop
            if isinstance(start, str):
                start = parseAllString(next_expression, start)
            if isinstance(stop, str):
                stop = parseAllString(next_expression, stop)
            return BitSelection(self, start, stop)
        elif isinstance(key, str):
            key = parseAllString(next_expression, key)
            return Subscript(self, key)
        else:
            return Subscript(self, key)

    def __getattr__(self, name):
        if name not in self.__dict__:
            return Dot(self, Identifier(name))
        else:
            raise AttributeError("'{}' object ha no attribute '{}'"
                                 .format(type(self).__name__, name))

    def word1(self):
        return Conversion("word1", self)

    def bool(self):
        return Conversion("bool", self)

    def toint(self):
        return Conversion("toint", self)

    def signed(self):
        return Conversion("signed", self)

    def unsigned(self):
        return Conversion("unsigned", self)

    def next(self):
        return Next(self)

    def init(self):
        return Init(self)

    def concat(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Concat(self, other)

    def union(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Union(self, other)

    def in_(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return In(self, other)

    def ite(self, true_expr, false_expr):
        from .parser import parseAllString, next_expression
        if isinstance(true_expr, str):
            true_expr = parseAllString(next_expression, true_expr)
        if isinstance(false_expr, str):
            false_expr = parseAllString(next_expression, false_expr)
        return Ite(self, true_expr, false_expr)

    def iff(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Iff(self, other)

    def implies(self, other):
        from .parser import parseAllString, next_expression
        if isinstance(other, str):
            other = parseAllString(next_expression, other)
        return Implies(self, other)

    def __deepcopy__(self, memo):
        raise NotImplementedError("Should be implemented by subclasses.")

    def to_node(self):
        """
        Translate the element into a Node instance.
        """
        from . import node
        from .parser import parse_next_expression
        parsed = parse_next_expression(str(self))
        res = node.Node.from_ptr(node.find_hierarchy(parsed))
        nsnode.free_node(parsed)
        return res

    @classmethod
    def from_string(cls, expr):
        """
        Create a new Expression from the given string `expr`.
        """
        from .parser import parseAllString, next_expression
        return parseAllString(next_expression, expr)
from .exception import NuSMVParsingError
from .utils import update
from .model import (Identifier, Self, Dot, ArrayAccess, Trueexp, Falseexp,
                    NumericalConst, NumberWord, RangeConst,
                    Conversion, WordFunction, Count, Next, Smallinit, Case,
                    Subscript, BitSelection, Set, Not, Concat,
                    Minus, Mult, Div, Mod, Add, Sub, LShift, RShift, Union, In,
                    Equal, NotEqual, Lt, Gt, Le, Ge, And, Or, Xor, Xnor, Ite,
                    Iff, Implies, ArrayExpr,
                    Boolean, Word, Scalar, Range, Array, Modtype,
                    Variables, InputVariables, FrozenVariables, Defines,
                    Assigns, Constants, Trans, Init, Invar, Fairness, Justice,
                    Compassion,
                    Expression)
from pynusmv_lower_interface.nusmv.parser import parser as nsparser
from pynusmv_lower_interface.nusmv.node import node as nsnode
from pyparsing import (Word as PWord, Forward, Optional, Literal,
                       OneOrMore, FollowedBy, Suppress, ZeroOrMore,
                       Combine, Group,
                       oneOf, delimitedList, restOfLine,
                       alphas, alphanums, nums,
                       ParserElement)
from collections import OrderedDict
from functools import reduce
    from .model import ModuleMetaClass, Module as ModuleClass

_ite = Forward()
_ite <<= _or + Optional("?" + _ite + ":" + _ite)
_ite.setParseAction(lambda s, l, t:
                    t[0] if len(t) <= 1 else Ite(t[0], t[2], t[4]))

_iff = _ite + ZeroOrMore("<->" + _ite)
# pylint: disable=unnecessary-lambda
_iff.setParseAction(lambda s, l, t: reduce(lambda e, n: Iff(e, n),
                                           t[0:1] + t[2::2]))

_implies = Forward()
_implies <<= _iff + ZeroOrMore("->" + _implies)
_implies.setParseAction(lambda s, l, t: reduce(lambda e, n: Implies(n, e),
                                               t[0:1] + t[2::2]))

_basic_expr <<= _implies

simple_expression <<= _basic_expr
next_expression = _basic_expr

# Type specifier
_simple_type_specifier = Forward()

_boolean_type = Literal("boolean")
_boolean_type.setParseAction(lambda s, l, t: Boolean())

_word_type = (Optional(Literal("unsigned") | Literal("signed"))
              + Literal("word") + Suppress("[") + _basic_expr + Suppress("]"))
_word_type.setParseAction(lambda s, l, t: Word(t[1]) if t[0] == "word"
                          else Word(t[2], sign=t[0]))

_enum_type = (Suppress("{")
              + delimitedList(_integer_number | _symbolic_constant)
              + Suppress("}"))
_enum_type.setParseAction(lambda s, l, t: Scalar(t))

_range_type = _shift + Suppress("..") + _shift
_range_type.setParseAction(lambda s, l, t: Range(t[0], t[1]))

_array_type = (Suppress("array") + _shift + Suppress("..") + _shift
               + Suppress("of") + _simple_type_specifier)
_array_type.setParseAction(lambda s, l, t: Array(t[0], t[1], t[2]))

_simple_type_specifier <<= (_boolean_type
                            | _word_type
                            | _enum_type
                            | _array_type
                            | _range_type)

_module_type_specifier = (Optional("process") + identifier
                          + Optional(Suppress("(")
                                     +
                                     Optional(delimitedList(simple_expression))
                                     + Suppress(")")))
_module_type_specifier.setParseAction(
    lambda s, l, t: Modtype(t[1], t[2:], process=True)
    if t[0] == "process"
    else Modtype(t[0], t[1:]))

type_identifier = _simple_type_specifier | _module_type_specifier

# Variables
_var_declaration = identifier + Suppress(":") + type_identifier + Suppress(";")
_var_section_body = OneOrMore(_var_declaration)
_var_section_body.setParseAction(lambda s, l, t:
                                 OrderedDict(zip(t[::2], t[1::2])))
var_section = Suppress("VAR") + _var_section_body
var_section.setParseAction(lambda s, l, t: Variables(t[0]))

_ivar_declaration = (identifier + Suppress(":") + _simple_type_specifier
                     + Suppress(";"))
_ivar_section_body = OneOrMore(_ivar_declaration)
_ivar_section_body.setParseAction(lambda s, l, t:
                                  OrderedDict(zip(t[::2], t[1::2])))
ivar_section = Suppress("IVAR") + _ivar_section_body
ivar_section.setParseAction(lambda s, l, t: InputVariables(t[0]))

_frozenvar_declaration = (identifier + Suppress(":") + _simple_type_specifier
                          + Suppress(";"))
_frozenvar_section_body = OneOrMore(_frozenvar_declaration)
_frozenvar_section_body.setParseAction(lambda s, l, t:
                                       OrderedDict(zip(t[::2], t[1::2])))
frozenvar_section = Suppress("FROZENVAR") + _frozenvar_section_body
frozenvar_section.setParseAction(lambda s, l, t: FrozenVariables(t[0]))

# DEFINE and CONSTANTS
_array_expression = Forward()
_array_expression <<= ( Suppress("[") + Group(delimitedList(next_expression))
                        + Suppress("]")
                      | Suppress("[") + Group(delimitedList(_array_expression))
                        + Suppress("]"))
_define = _array_expression | next_expression
_define_declaration = (identifier + Suppress(":=") + _define + Suppress(";"))

def _handle_define_body(s, l, t):
    # pylint: disable=unused-argument
    b = OrderedDict()
    for identifier, body in zip(t[::2], t[1::2]):
        if not isinstance(body, Expression):
            body = ArrayExpr(body)
        b[identifier] = body
    return b
_define_section_body = OneOrMore(_define_declaration)
_define_section_body.setParseAction(_handle_define_body)
define_section = Suppress("DEFINE") + _define_section_body
define_section.setParseAction(lambda s, l, t: Defines(t[0]))

_constants_section_body = delimitedList(identifier) + Suppress(";")
_constants_section_body.setParseAction(lambda s, l, t: list(t))
constants_section = Suppress("CONSTANTS") + _constants_section_body
constants_section.setParseAction(lambda s, l, t: Constants(list(t)))

# ASSIGN, TRANS, INIT, INVAR, FAIRNESS
_assign_identifier = (Literal("init") + Suppress("(") + complex_identifier
                      + Suppress(")")
                      | Literal("next") + Suppress("(") + complex_identifier
                      + Suppress(")")
                      | complex_identifier)
_assign_identifier.setParseAction(lambda s, l, t:

                                  Smallinit(t[1]) if t[0] == "init"