Returns QASM code for the given value, if possible.

    Different values require different sets of arguments. The general rule of
    thumb is that circuits don't need any, operations need a `QasmArgs`, and
    gates need both a `QasmArgs` and `qubits`.

    Args:
        val: The value to turn into QASM code.
        args: A `QasmArgs` object to pass into the value's `_qasm_` method.
            This is for needed for objects that only have a local idea of what's
            going on, e.g. a `cirq.Operation` in a bigger `cirq.Circuit`
            involving qubits that the operation wouldn't otherwise know about.
        qubits: A list of qubits that the value is being applied to. This is
            needed for `cirq.Gate` values, which otherwise wouldn't know what
            qubits to talk about.
        default: A default result to use if the value doesn't have a
            `_qasm_` method or that method returns `NotImplemented` or
            `None`. If not specified, undecomposable values cause a `TypeError`.

    Returns:
        The result of `val._qasm_(...)`, if `val` has a `_qasm_`
        method and it didn't return `NotImplemented` or `None`. Otherwise
        `default` is returned, if it was specified. Otherwise an error is
        raised.

    TypeError:
        `val` didn't have a `_qasm_` method (or that method returned
        `NotImplemented` or `None`) and `default` wasn't set.

def qasm(val: Any,
         *,
         args: Optional[QasmArgs] = None,
         qubits: Optional[Iterable['cirq.Qid']] = None,
         default: TDefault = RaiseTypeErrorIfNotProvided
         ) -> Union[str, TDefault]:
    """Returns QASM code for the given value, if possible.

    Different values require different sets of arguments. The general rule of
    thumb is that circuits don't need any, operations need a `QasmArgs`, and
    gates need both a `QasmArgs` and `qubits`.

    Args:
        val: The value to turn into QASM code.
        args: A `QasmArgs` object to pass into the value's `_qasm_` method.
            This is for needed for objects that only have a local idea of what's
            going on, e.g. a `cirq.Operation` in a bigger `cirq.Circuit`
            involving qubits that the operation wouldn't otherwise know about.
        qubits: A list of qubits that the value is being applied to. This is
            needed for `cirq.Gate` values, which otherwise wouldn't know what
            qubits to talk about.
        default: A default result to use if the value doesn't have a
            `_qasm_` method or that method returns `NotImplemented` or
            `None`. If not specified, undecomposable values cause a `TypeError`.

    Returns:
        The result of `val._qasm_(...)`, if `val` has a `_qasm_`
        method and it didn't return `NotImplemented` or `None`. Otherwise
        `default` is returned, if it was specified. Otherwise an error is
        raised.

    TypeError:
        `val` didn't have a `_qasm_` method (or that method returned
        `NotImplemented` or `None`) and `default` wasn't set.
    """
    method = getattr(val, '_qasm_', None)
    result = NotImplemented
    if method is not None:
        kwargs = {}  # type: Dict[str, Any]
        if args is not None:
            kwargs['args'] = args
        if qubits is not None:
            kwargs['qubits'] = tuple(qubits)
        result = method(**kwargs)
    if result is not None and result is not NotImplemented:
        return result

    if default is not RaiseTypeErrorIfNotProvided:
        return default
    if method is None:
        raise TypeError("object of type '{}' "
                        "has no _qasm_ method.".format(type(val)))
    raise TypeError("object of type '{}' does have a _qasm_ method, "
                    "but it returned NotImplemented or None.".format(type(val)))