From dbe71c715edc0eaa22a7d623da0851c6627a81ac Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 28 Jan 2015 10:52:13 +0100 Subject: [PATCH] documented new C++ support --- doc/idetools.txt | 2 +- doc/nimc.txt | 190 +++++++++++++++++++++++++++--- lib/pure/collections/critbits.nim | 11 +- lib/pure/collections/intsets.nim | 2 +- lib/pure/collections/queues.nim | 2 +- lib/pure/collections/sets.nim | 3 +- lib/pure/collections/tables.nim | 3 +- todo.txt | 1 - 8 files changed, 185 insertions(+), 29 deletions(-) diff --git a/doc/idetools.txt b/doc/idetools.txt index 6a10e2a8c..48197f8bf 100644 --- a/doc/idetools.txt +++ b/doc/idetools.txt @@ -421,7 +421,7 @@ returned by idetools returns also the pragmas for the proc. | **Docstring**: docstring if available. .. code-block:: nim - Open(filename, fmWrite) + open(filename, fmWrite) --> col 2: system.Open col 3: proc (var File, string, FileMode, int): bool col 7: diff --git a/doc/nimc.txt b/doc/nimc.txt index 7aa7afb3a..80fcf927b 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -393,12 +393,18 @@ Use two backticks to produce a single verbatim backtick. ImportCpp pragma ----------------- +---------------- + +**Note**: `c2nim `_ can parse a large subset of C++ and knows +about the ``importcpp`` pragma pattern language. It is not necessary +to know all the details described here. + + Similar to the `importc pragma for C `_, the -``importcpp`` pragma can be used to import `C++`:idx: methods. The generated -code then uses the C++ method calling syntax: ``obj->method(arg)``. In -addition with the ``header`` and ``emit`` pragmas this allows *sloppy* -interfacing with libraries written in C++: +``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols +in general. The generated code then uses the C++ method calling +syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit`` +pragmas this allows *sloppy* interfacing with libraries written in C++: .. code-block:: Nim # Horrible example of how to interface with a C++ engine ... ;-) @@ -418,18 +424,168 @@ interfacing with libraries written in C++: irr = "" type - IrrlichtDeviceObj {.final, header: irr, importc: "IrrlichtDevice".} = object + IrrlichtDeviceObj {.final, header: irr, + importcpp: "IrrlichtDevice".} = object IrrlichtDevice = ptr IrrlichtDeviceObj - proc createDevice(): PIrrlichtDevice {. - header: irr, importc: "createDevice".} - proc run(device: PIrrlichtDevice): bool {. - header: irr, importcpp: "run".} - + proc createDevice(): IrrlichtDevice {. + header: irr, importcpp: "createDevice(@)".} + proc run(device: IrrlichtDevice): bool {. + header: irr, importcpp: "#.run(@)".} + The compiler needs to be told to generate C++ (command ``cpp``) for this to work. The conditional symbol ``cpp`` is defined when the compiler -emits C++ code. - +emits C++ code. + + +Namespaces +~~~~~~~~~~ + +The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace`` +declarations. It is usually much better to instead refer to the imported name +via the ``namespace::identifier`` notation: + +.. code-block:: nim + type + IrrlichtDeviceObj {.final, header: irr, + importcpp: "irr::IrrlichtDevice".} = object + + +Importcpp for enums +~~~~~~~~~~~~~~~~~~~ + +When ``importcpp`` is applied to an enum type the numerical enum values are +annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``. +(This turned out to be the simplest way to implement it.) + + +Importcpp for procs +~~~~~~~~~~~~~~~~~~~ + +Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern +language for maximum flexibility: + +- A hash ``#`` symbol is replaced by the first or next argument. +- A dot following the hash ``#.`` indicates that the call should use C++'s dot + or arrow notation. +- An at symbol ``@`` is replaced by the remaining arguments, separated by + commas. + +For example: + +.. code-block:: nim + proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".} + var x: ptr CppObj + cppMethod(x[], 1, 2, 3) + +Produces: + +.. code-block:: C + x->CppMethod(1, 2, 3) + +As a special rule to keep backwards compatibility with older versions of the +``importcpp`` pragma, if there is no special pattern +character (any of ``# ' @``) at all, C++'s +dot or arrow notation is assumed, so the above example can also be written as: + +.. code-block:: nim + proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".} + +Note that the pattern language naturally also covers C++'s operator overloading +capabilities: + +.. code-block:: nim + proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".} + proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".} + + +- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9 + is replaced by the i'th parameter *type*. The 0th position is the result + type. This can be used to pass types to C++ function templates. Between + the ``'`` and the digit an asterisk can be used to get to the base type + of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.) + Two stars can be used to get to the element type of the element type etc. + +For example: + +.. code-block:: nim + + type Input {.importcpp: "System::Input".} = object + proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".} + + let x: ptr Input = getSubsystem[Input]() + +Produces: + +.. code-block:: C + x = SystemManager::getSubsystem() + + +- ``#@`` is a special case to support a ``cnew`` operation. It is required so + that the call expression is inlined directly, without going through a + temporary location. This is only required to circumvent a limitation of the + current code generator. + +For example C++'s ``new`` operator can be "imported" like this: + +.. code-block:: nim + proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.} + + # constructor of 'Foo': + proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".} + + let x = cnew constructFoo(3, 4) + +Produces: + +.. code-block:: C + x = new Foo(3, 4) + +However, depending on the use case ``new Foo`` can also be wrapped like this +instead: + +.. code-block:: nim + proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".} + + let x = newFoo(3, 4) + + +Wrapping destructors +~~~~~~~~~~~~~~~~~~~~ + +Since Nim generates C++ directly, any destructor is called implicitly by the +C++ compiler at the scope exits. This means that often one can get away with +not wrapping the destructor at all! However when it needs to be invoked +explicitly, it needs to be wrapped. But the pattern language already provides +everything that is required for that: + +.. code-block:: nim + proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".} + + +Importcpp for objects +~~~~~~~~~~~~~~~~~~~~~ + +Generic ``importcpp``'ed objects are mapped to C++ templates. This means that +you can import C++'s templates rather easily without the need for a pattern +language for object types: + +.. code-block:: nim + type + StdMap {.importcpp: "std::map", header: "".} [K, V] = object + proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. + importcpp: "#[#] = #".} + + var x: StdMap[cint, cdouble] + x[6] = 91.4 + + +Produces: + +.. code-block:: C + std::map x; + x[6] = 91.4; + ImportObjC pragma ----------------- @@ -607,7 +763,7 @@ line is an incomplete statement to be continued these rules are used: Nim for embedded systems ======================== -The standard library can be avoided to a point where C code generation +The standard library can be avoided to a point where C code generation for 16bit micro controllers is feasible. Use the `standalone`:idx: target (``--os:standalone``) for a bare bones standard library that lacks any OS features. @@ -619,9 +775,9 @@ For example, to generate code for an `AVR`:idx: processor use this command:: nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim -For the ``standalone`` target you need to provide -a file ``panicoverride.nim``. -See ``tests/manyloc/standalone/panicoverride.nim`` for an example +For the ``standalone`` target one needs to provide +a file ``panicoverride.nim``. +See ``tests/manyloc/standalone/panicoverride.nim`` for an example implementation. diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 8f506409b..06babc6bb 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -12,7 +12,7 @@ ## by Adam Langley. type - NodeObj[T] = object {.pure, final, acyclic.} + NodeObj[T] = object {.acyclic.} byte: int ## byte index of the difference otherbits: char case isLeaf: bool @@ -23,11 +23,10 @@ type val: T Node[T] = ref NodeObj[T] - CritBitTree*[T] = object {. - pure, final.} ## The crit bit tree can either be used - ## as a mapping from strings to - ## some type ``T`` or as a set of - ## strings if ``T`` is void. + CritBitTree*[T] = object ## The crit bit tree can either be used + ## as a mapping from strings to + ## some type ``T`` or as a set of + ## strings if ``T`` is void. root: Node[T] count: int diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 5d9c3f445..b46e040ca 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -8,7 +8,7 @@ # ## The ``intsets`` module implements an efficient int set implemented as a -## sparse bit set. +## `sparse bit set`:idx:. ## **Note**: Since Nim currently does not allow the assignment operator to ## be overloaded, ``=`` for int sets performs some rather meaningless shallow ## copy; use ``assign`` to get a deep copy. diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim index defce657f..fb4d35310 100644 --- a/lib/pure/collections/queues.nim +++ b/lib/pure/collections/queues.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## Implementation of a queue. The underlying implementation uses a ``seq``. +## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``. ## Note: For inter thread communication use ## a `TChannel `_ instead. diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 8af0b3118..4cc46149e 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -7,7 +7,8 @@ # distribution, for details about the copyright. # -## The ``sets`` module implements an efficient hash set and ordered hash set. +## The ``sets`` module implements an efficient `hash set`:idx: and +## ordered hash set. ## ## Hash sets are different from the `built in set type ## `_. Sets allow you to store any value that can be diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index d92deb1b3..9dcc97148 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -7,7 +7,8 @@ # distribution, for details about the copyright. # -## The ``tables`` module implements variants of an efficient hash table that is +## The ``tables`` module implements variants of an efficient `hash table`:idx: +## (also often named `dictionary`:idx: in other programming languages) that is ## a mapping from keys to values. ``Table`` is the usual hash table, ## ``OrderedTable`` is like ``Table`` but remembers insertion order ## and ``CountTable`` is a mapping from a key to its number of occurances. diff --git a/todo.txt b/todo.txt index 173a68567..fa337fdcf 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,6 @@ version 0.10 ============ -- document the improved c++ support - improve the docs for inheritance - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!