diff options
Diffstat (limited to 'sphinx/specification_files.rst')
-rw-r--r-- | sphinx/specification_files.rst | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/sphinx/specification_files.rst b/sphinx/specification_files.rst new file mode 100644 index 0000000..6ba3aba --- /dev/null +++ b/sphinx/specification_files.rst @@ -0,0 +1,499 @@ +SIP Specification Files +======================= + +A SIP specification consists of some C/C++ type and function declarations and +some directives. The declarations may contain annotations which provide SIP +with additional information that cannot be expressed in C/C++. SIP does not +include a full C/C++ parser. + +It is important to understand that a SIP specification describes the Python +API, i.e. the API available to the Python programmer when they ``import`` the +generated module. It does not have to accurately represent the underlying +C/C++ library. There is nothing wrong with omitting functions that make +little sense in a Python context, or adding functions implemented with +handwritten code that have no C/C++ equivalent. It is even possible (and +sometimes necessary) to specify a different super-class hierarchy for a C++ +class. All that matters is that the generated code compiles properly. + +In most cases the Python API matches the C/C++ API. In some cases handwritten +code (see :directive:`%MethodCode`) is used to map from one to the other +without SIP having to know the details itself. However, there are a few cases +where SIP generates a thin wrapper around a C++ method or constructor (see +:ref:`ref-derived-classes`) and needs to know the exact C++ signature. To deal +with these cases SIP allows two signatures to be specified. For example:: + + class Klass + { + public: + // The Python signature is a tuple, but the underlying C++ signature + // is a 2 element array. + Klass(SIP_PYTUPLE) [(int *)]; + %MethodCode + int iarr[2]; + + if (PyArg_ParseTuple(a0, "ii", &iarr[0], &iarr[1])) + { + // Note that we use the SIP generated derived class + // constructor. + Py_BEGIN_ALLOW_THREADS + sipCpp = new sipKlass(iarr); + Py_END_ALLOW_THREADS + } + %End + }; + + +Syntax Definition +----------------- + +The following is a semi-formal description of the syntax of a specification +file. + +.. parsed-literal:: + + *specification* ::= {*module-statement*} + + *module-statement* ::= [*module-directive* | *statement*] + + *module-directive* ::= [ + :directive:`%API` | + :directive:`%CModule` | + :directive:`%CompositeModule` | + :directive:`%ConsolidatedModule` | + :directive:`%Copying` | + :directive:`%DefaultEncoding` | + :directive:`%DefaultMetatype` | + :directive:`%DefaultSupertype` | + :directive:`%Doc` | + :directive:`%ExportedDoc` | + :directive:`%ExportedHeaderCode` | + :directive:`%Feature` | + :directive:`%Import` | + :directive:`%Include` | + :directive:`%InitialisationCode` | + :directive:`%License` | + :directive:`%MappedType` | + :directive:`%Module` | + :directive:`%ModuleCode` | + :directive:`%ModuleHeaderCode` | + :directive:`%OptionalInclude` | + :directive:`%Platforms` | + :directive:`%PreInitialisationCode` | + :directive:`%PostInitialisationCode` | + :directive:`%Timeline` | + :directive:`%UnitCode` | + *mapped-type-template*] + + *statement* :: [*class-statement* | *function* | *variable*] + + *class-statement* :: [ + :directive:`%If` | + *class* | + *class-template* | + *enum* | + *namespace* | + *opaque-class* | + *operator* | + *struct* | + *typedef* | + *exception*] + + *class* ::= **class** *name* [**:** *super-classes*] [*class-annotations*] + **{** {*class-line*} **};** + + *super-classes* ::= *name* [**,** *super-classes*] + + *class-line* ::= [ + *class-statement* | + :directive:`%BIGetBufferCode` | + :directive:`%BIGetReadBufferCode` | + :directive:`%BIGetWriteBufferCode` | + :directive:`%BIGetSegCountCode` | + :directive:`%BIGetCharBufferCode` | + :directive:`%BIReleaseBufferCode` | + :directive:`%ConvertToSubClassCode` | + :directive:`%ConvertToTypeCode` | + :directive:`%Docstring` | + :directive:`%GCClearCode` | + :directive:`%GCTraverseCode` | + :directive:`%PickleCode` | + :directive:`%TypeCode` | + :directive:`%TypeHeaderCode` | + *constructor* | + *destructor* | + *method* | + *static-method* | + *virtual-method* | + *special-method* | + *operator* | + *virtual-operator* | + *class-variable* | + **public:** | + **public Q_SLOTS:** | + **public slots:** | + **protected:** | + **protected Q_SLOTS:** | + **protected slots:** | + **private:** | + **private Q_SLOTS:** | + **private slots:** | + **Q_SIGNALS:** | + **signals:**] + + *constructor* ::= [**explicit**] *name* **(** [*argument-list*] **)** + [*exceptions*] [*function-annotations*] + [*c++-constructor-signature*] **;** [:directive:`%Docstring`] + [:directive:`%MethodCode`] + + *c++-constructor-signature* ::= **[(** [*argument-list*] **)]** + + *destructor* ::= [**virtual**] **~** *name* **()** [*exceptions*] [**= 0**] + [*function-annotations*] **;** [:directive:`%MethodCode`] + [:directive:`%VirtualCatcherCode`] + + *method* ::= [**Q_SIGNAL**] [**Q_SLOT**] *type* *name* **(** + [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] + [*function-annotations*] [*c++-signature*] **;** + [:directive:`%Docstring`] [:directive:`%MethodCode`] + + *c++-signature* ::= **[** *type* **(** [*argument-list*] **)]** + + *static-method* ::= **static** *function* + + *virtual-method* ::= [**Q_SIGNAL**] [**Q_SLOT**] **virtual** *type* *name* + **(** [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] + [*function-annotations*] [*c++-signature*] **;** + [:directive:`%MethodCode`] [:directive:`%VirtualCatcherCode`] + + *special-method* ::= *type* *special-method-name* + **(** [*argument-list*] **)** [*function-annotations*] **;** + [:directive:`%MethodCode`] + + *special-method-name* ::= [**__abs__** | **__add__** | **__and__** | + **__bool__** | **__call__** | **__cmp__** | **__contains__** | + **__delitem__** | **__div__** | **__eq__** | **__float__** | + **__floordiv__** | **__ge__** | **__getitem__** | **__gt__** | + **__hash__** | **__iadd__** | **__iand__** | **__idiv__** | + **__ifloordiv__** | **__ilshift__** | **__imod__** | **__imul__** | + **__index__** | **__int__** | **__invert__** | **__ior__** | + **__irshift__** | **__isub__** | **__iter__** | **__itruediv__** | + **__ixor__** | **__le__** | **__len__** | **__long__** | + **__lshift__** | **__lt__** | **__mod__** | **__mul__** | + **__ne__** | **__neg__** | **__next__** | **__nonzero__** | + **__or__** | **__pos__** | **__repr__** | **__rshift__** | + **__setitem__** | **__str__** | **__sub__** | **__truediv__** | + **__xor__**] + + *operator* ::= *operator-type* + **(** [*argument-list*] **)** [**const**] [*exceptions*] + [*function-annotations*] **;** [:directive:`%MethodCode`] + + *virtual-operator* ::= **virtual** *operator-type* + **(** [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] + [*function-annotations*] **;** [:directive:`%MethodCode`] + [:directive:`%VirtualCatcherCode`] + + *operatator-type* ::= [ *operator-function* | *operator-cast* ] + + *operator-function* ::= *type* **operator** *operator-name* + + *operator-cast* ::= **operator** *type* + + *operator-name* ::= [**+** | **-** | ***** | **/** | **%** | **&** | + **|** | **^** | **<<** | **>>** | **+=** | **-=** | ***=** | + **/=** | **%=** | **&=** | **|=** | **^=** | **<<=** | **>>=** | + **~** | **()** | **[]** | **<** | **<=** | **==** | **!=** | + **>** | **>>=** | **=**] + + *class-variable* ::= [**static**] *variable* + + *class-template* :: = **template** **<** *type-list* **>** *class* + + *mapped-type-template* :: = **template** **<** *type-list* **>** + :directive:`%MappedType` + + *enum* ::= **enum** [*name*] [*enum-annotations*] **{** {*enum-line*} **};** + + *enum-line* ::= [:directive:`%If` | *name* [*enum-annotations*] **,** + + *function* ::= *type* *name* **(** [*argument-list*] **)** [*exceptions*] + [*function-annotations*] **;** [:directive:`%Docstring`] + [:directive:`%MethodCode`] + + *namespace* ::= **namespace** *name* **{** {*namespace-line*} **};** + + *namespace-line* ::= [:directive:`%TypeHeaderCode` | *statement*] + + *opaque-class* ::= **class** *scoped-name* **;** + + *struct* ::= **struct** *name* **{** {*class-line*} **};** + + *typedef* ::= **typedef** [*typed-name* | *function-pointer*] + *typedef-annotations* **;** + + *variable*::= *typed-name* [*variable-annotations*] **;** + [:directive:`%AccessCode`] [:directive:`%GetCode`] + [:directive:`%SetCode`] + + *exception* ::= :directive:`%Exception` *exception-name* [*exception-base*] + **{** [:directive:`%TypeHeaderCode`] :directive:`%RaiseCode` **};** + + *exception-name* ::= *scoped-name* + + *exception-base* ::= **(** [*exception-name* | *python-exception*] **)** + + *python-exception* ::= [**SIP_Exception** | **SIP_StopIteration** | + **SIP_StandardError** | **SIP_ArithmeticError** | + **SIP_LookupError** | **SIP_AssertionError** | + **SIP_AttributeError** | **SIP_EOFError** | + **SIP_FloatingPointError** | **SIP_EnvironmentError** | + **SIP_IOError** | **SIP_OSError** | **SIP_ImportError** | + **SIP_IndexError** | **SIP_KeyError** | **SIP_KeyboardInterrupt** | + **SIP_MemoryError** | **SIP_NameError** | **SIP_OverflowError** | + **SIP_RuntimeError** | **SIP_NotImplementedError** | + **SIP_SyntaxError** | **SIP_IndentationError** | **SIP_TabError** | + **SIP_ReferenceError** | **SIP_SystemError** | **SIP_SystemExit** | + **SIP_TypeError** | **SIP_UnboundLocalError** | + **SIP_UnicodeError** | **SIP_UnicodeEncodeError** | + **SIP_UnicodeDecodeError** | **SIP_UnicodeTranslateError** | + **SIP_ValueError** | **SIP_ZeroDivisionError** | + **SIP_WindowsError** | **SIP_VMSError**] + + *exceptions* ::= **throw (** [*exception-list*] **)** + + *exception-list* ::= *scoped-name* [**,** *exception-list*] + + *argument-list* ::= *argument* [**,** *argument-list*] [**,** **...**] + + *argument* ::= [ + *type* [*name*] [*argument-annotations*] [*default-value*] | + :stype:`SIP_ANYSLOT` [*default-value*] | + :stype:`SIP_QOBJECT` | + :stype:`SIP_RXOBJ_CON` | + :stype:`SIP_RXOBJ_DIS` | + :stype:`SIP_SIGNAL` [*default-value*] | + :stype:`SIP_SLOT` [*default-value*] | + :stype:`SIP_SLOT_CON` | + :stype:`SIP_SLOT_DIS`] + + *default-value* ::= **=** *expression* + + *expression* ::= [*value* | *value* *binary-operator* *expression*] + + *value* ::= [*unary-operator*] *simple-value* + + *simple-value* ::= [*scoped-name* | *function-call* | *real-value* | + *integer-value* | *boolean-value* | *string-value* | + *character-value*] + + *typed-name*::= *type* *name* + + *function-pointer*::= *type* **(*** *name* **)(** [*type-list*] **)** + + *type-list* ::= *type* [**,** *type-list*] + + *function-call* ::= *scoped-name* **(** [*value-list*] **)** + + *value-list* ::= *value* [**,** *value-list*] + + *real-value* ::= a floating point number + + *integer-value* ::= a number + + *boolean-value* ::= [**true** | **false**] + + *string-value* ::= **"** {*character*} **"** + + *character-value* ::= **'** *character* **'** + + *unary-operator* ::= [**!** | **~** | **-** | **+**] + + *binary-operator* ::= [**-** | **+** | ***** | **/** | **&** | **|**] + + *argument-annotations* ::= see :ref:`ref-arg-annos` + + *class-annotations* ::= see :ref:`ref-class-annos` + + *enum-annotations* ::= see :ref:`ref-enum-annos` + + *function-annotations* ::= see :ref:`ref-function-annos` + + *typedef-annotations* ::= see :ref:`ref-typedef-annos` + + *variable-annotations* ::= see :ref:`ref-variable-annos` + + *type* ::= [**const**] *base-type* {*****} [**&**] + + *type-list* ::= *type* [**,** *type-list*] + + *base-type* ::= [*scoped-name* | *template* | **struct** *scoped-name* | + **char** | **signed char** | **unsigned char** | **wchar_t** | + **int** | **unsigned** | **unsigned int** | + **short** | **unsigned short** | + **long** | **unsigned long** | + **long long** | **unsigned long long** | + **float** | **double** | + **bool** | + **void** | + :stype:`SIP_PYCALLABLE` | + :stype:`SIP_PYDICT` | + :stype:`SIP_PYLIST` | + :stype:`SIP_PYOBJECT` | + :stype:`SIP_PYSLICE` | + :stype:`SIP_PYTUPLE` | + :stype:`SIP_PYTYPE`] + + *scoped-name* ::= *name* [**::** *scoped-name*] + + *template* ::= *scoped-name* **<** *type-list* **>** + + *dotted-name* ::= *name* [**.** *dotted-name*] + + *name* ::= _A-Za-z {_A-Za-z0-9} + +Here is a short list of differences between C++ and the subset supported by +SIP that might trip you up. + + - SIP does not support the use of ``[]`` in types. Use pointers instead. + + - A global ``operator`` can only be defined if its first argument is a + class or a named enum that has been wrapped in the same module. + + - Variables declared outside of a class are effectively read-only. + + - A class's list of super-classes doesn't not include any access specifier + (e.g. ``public``). + + +Variable Numbers of Arguments +----------------------------- + +SIP supports the use of ``...`` as the last part of a function signature. Any +remaining arguments are collected as a Python tuple. + + +Additional SIP Types +-------------------- + +SIP supports a number of additional data types that can be used in Python +signatures. + + +.. sip-type:: SIP_ANYSLOT + +This is both a ``const char *`` and a ``PyObject *`` that is used as the type +of the member instead of ``const char *`` in functions that implement the +connection or disconnection of an explicitly generated signal to a slot. +Handwritten code must be provided to interpret the conversion correctly. + + +.. sip-type:: SIP_PYCALLABLE + +This is a ``PyObject *`` that is a Python callable object. + + +.. sip-type:: SIP_PYDICT + +This is a ``PyObject *`` that is a Python dictionary object. + + +.. sip-type:: SIP_PYLIST + +This is a ``PyObject *`` that is a Python list object. + + +.. sip-type:: SIP_PYOBJECT + +This is a ``PyObject *`` of any Python type. + + +.. sip-type:: SIP_PYSLICE + +This is a ``PyObject *`` that is a Python slice object. + + +.. sip-type:: SIP_PYTUPLE + +This is a ``PyObject *`` that is a Python tuple object. + + +.. sip-type:: SIP_PYTYPE + +This is a ``PyObject *`` that is a Python type object. + + +.. sip-type:: SIP_QOBJECT + +This is a ``QObject *`` that is a C++ instance of a class derived from Qt's +``QObject`` class. + + +.. sip-type:: SIP_RXOBJ_CON + +This is a ``QObject *`` that is a C++ instance of a class derived from Qt's +``QObject`` class. It is used as the type of the receiver instead of ``const +QObject *`` in functions that implement a connection to a slot. + + +.. sip-type:: SIP_RXOBJ_DIS + +This is a ``QObject *`` that is a C++ instance of a class derived from Qt's +``QObject`` class. It is used as the type of the receiver instead of ``const +QObject *`` in functions that implement a disconnection from a slot. + + +.. sip-type:: SIP_SIGNAL + +This is a ``const char *`` that is used as the type of the signal instead of +``const char *`` in functions that implement the connection or disconnection +of an explicitly generated signal to a slot. + + +.. sip-type:: SIP_SLOT + +This is a ``const char *`` that is used as the type of the member instead of +``const char *`` in functions that implement the connection or disconnection +of an explicitly generated signal to a slot. + + +.. sip-type:: SIP_SLOT_CON + +This is a ``const char *`` that is used as the type of the member instead of +``const char *`` in functions that implement the connection of an internally +generated signal to a slot. The type includes a comma separated list of types +that is the C++ signature of of the signal. + +To take an example, ``QAccel::connectItem()`` connects an internally generated +signal to a slot. The signal is emitted when the keyboard accelerator is +activated and it has a single integer argument that is the ID of the +accelerator. The C++ signature is:: + + bool connectItem(int id, const QObject *receiver, const char *member); + +The corresponding SIP specification is:: + + bool connectItem(int, SIP_RXOBJ_CON, SIP_SLOT_CON(int)); + + +.. sip-type:: SIP_SLOT_DIS + +This is a ``const char *`` that is used as the type of the member instead of +``const char *`` in functions that implement the disconnection of an +internally generated signal to a slot. The type includes a comma separated +list of types that is the C++ signature of of the signal. + + +Classic Division and True Division +---------------------------------- + +SIP supports the ``__div__`` and ``__truediv__`` special methods (and the +corresponding inplace versions) for both Python v2 and v3. + +For Python v2 the ``__div__`` method will be used for both classic and true +division if a ``__truediv__`` method is not defined. + +For Python v3 the ``__div__`` method will be used for true division if a +``__truediv__`` method is not defined. + +For all versions of Python, if both methods are defined then ``__div__`` +should be defined first. |