# Source code for ufl.core.terminal

    """This module defines the Terminal class.

    Terminal the superclass for all types that are terminal nodes in an expression tree.
    """
    # Copyright (C) 2008-2016 Martin Sandve Alnæs
    #
    # This file is part of UFL (https://www.fenicsproject.org)
    #
    # SPDX-License-Identifier:    LGPL-3.0-or-later
    #
    # Modified by Anders Logg, 2008
    # Modified by Massimiliano Leoni, 2016

    import warnings

    from ufl.core.expr import Expr
    from ufl.core.ufl_type import ufl_type

    @ufl_type(is_abstract=True, is_terminal=True)
    class Terminal(Expr):
        """Base class for terminal objects.

        A terminal node in the UFL expression tree.
        """

        __slots__ = ()

        def __init__(self):
            """Initialise the terminal."""
            Expr.__init__(self)

        ufl_operands = ()
        ufl_free_indices = ()
        ufl_index_dimensions = ()

        def ufl_domains(self):
            """Return tuple of domains related to this terminal object."""
            raise NotImplementedError("Missing implementation of domains().")

        def evaluate(self, x, mapping, component, index_values, derivatives=()):
            """Get *self* from *mapping* and return the component asked for."""
            f = mapping.get(self)
            # No mapping, trying to evaluate self as a constant
            if f is None:
                try:
                    try:
                        f = float(self)
                    except TypeError:
                        f = complex(self)
                    if derivatives:
                        f = 0.0
                    return f
                except Exception:
                    pass
                # If it has an ufl_evaluate function, call it
                if hasattr(self, "ufl_evaluate"):
                    return self.ufl_evaluate(x, component, derivatives)
                # Take component if any
                warnings.warn(
                    f"Couldn't map '{self}' to a float, returning ufl object without evaluation."
                )
                f = self
                if component:
                    f = f[component]
                return f

            # Found a callable in the mapping
            if callable(f):
                if derivatives:
                    f = f(x, derivatives)
                else:
                    f = f(x)
            else:
                if derivatives:
                    return 0.0

            # Take component if any (expecting nested tuple)
            for c in component:
                f = f[c]
            return f

        def _ufl_signature_data_(self, renumbering):
            """Default signature data for of terminals just return the repr string."""
            return repr(self)

        def _ufl_compute_hash_(self):
            """Default hash of terminals just hash the repr string."""
            return hash(repr(self))

        def __eq__(self, other):
            """Default comparison of terminals just compare repr strings."""
            return repr(self) == repr(other)

    # --- Subgroups of terminals ---

    @ufl_type(is_abstract=True)
    class FormArgument(Terminal):
        """An abstract class for a form argument (a thing in a primal finite element space)."""

        __slots__ = ()

        def __init__(self):
            """Initialise the form argument."""
            Terminal.__init__(self)