manual split up into multiple files; documented the new concurrency system
This commit is contained in:
parent
e9dec2feed
commit
2c1f3f75f5
31 changed files with 6198 additions and 5901 deletions
477
doc/manual/pragmas.txt
Normal file
477
doc/manual/pragmas.txt
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
Pragmas
|
||||
=======
|
||||
|
||||
Pragmas are Nim's method to give the compiler additional information /
|
||||
commands without introducing a massive number of new keywords. Pragmas are
|
||||
processed on the fly during semantic checking. Pragmas are enclosed in the
|
||||
special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a
|
||||
first implementation to play with a language feature before a nicer syntax
|
||||
to access the feature becomes available.
|
||||
|
||||
|
||||
noSideEffect pragma
|
||||
-------------------
|
||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||
effects. This means that the proc/iterator only changes locations that are
|
||||
reachable from its parameters and the return value only depends on the
|
||||
arguments. If none of its parameters have the type ``var T``
|
||||
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
|
||||
As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
|
||||
pretends to be free of side effects, so that it can be used for debugging
|
||||
routines marked as ``noSideEffect``.
|
||||
|
||||
**Future directions**: ``func`` may become a keyword and syntactic sugar for a
|
||||
proc with no side effects:
|
||||
|
||||
.. code-block:: nim
|
||||
func `+` (x, y: int): int
|
||||
|
||||
|
||||
destructor pragma
|
||||
-----------------
|
||||
|
||||
The ``destructor`` pragma is used to mark a proc to act as a type destructor.
|
||||
Its usage is deprecated, use the ``override`` pragma instead.
|
||||
See `type bound operations`_.
|
||||
|
||||
|
||||
override pragma
|
||||
---------------
|
||||
|
||||
See `type bound operations`_ instead.
|
||||
|
||||
procvar pragma
|
||||
--------------
|
||||
The ``procvar`` pragma is used to mark a proc that it can be passed to a
|
||||
procedural variable.
|
||||
|
||||
|
||||
compileTime pragma
|
||||
------------------
|
||||
The ``compileTime`` pragma is used to mark a proc to be used at compile
|
||||
time only. No code will be generated for it. Compile time procs are useful
|
||||
as helpers for macros.
|
||||
|
||||
|
||||
noReturn pragma
|
||||
---------------
|
||||
The ``noreturn`` pragma is used to mark a proc that never returns.
|
||||
|
||||
|
||||
acyclic pragma
|
||||
--------------
|
||||
The ``acyclic`` pragma can be used for object types to mark them as acyclic
|
||||
even though they seem to be cyclic. This is an **optimization** for the garbage
|
||||
collector to not consider objects of this type as part of a cycle:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
PNode = ref TNode
|
||||
TNode {.acyclic, final.} = object
|
||||
left, right: PNode
|
||||
data: string
|
||||
|
||||
In the example a tree structure is declared with the ``TNode`` type. Note that
|
||||
the type definition is recursive and the GC has to assume that objects of
|
||||
this type may form a cyclic graph. The ``acyclic`` pragma passes the
|
||||
information that this cannot happen to the GC. If the programmer uses the
|
||||
``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
|
||||
memory, but nothing worse happens.
|
||||
|
||||
**Future directions**: The ``acyclic`` pragma may become a property of a
|
||||
``ref`` type:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
PNode = acyclic ref TNode
|
||||
TNode = object
|
||||
left, right: PNode
|
||||
data: string
|
||||
|
||||
|
||||
final pragma
|
||||
------------
|
||||
The ``final`` pragma can be used for an object type to specify that it
|
||||
cannot be inherited from.
|
||||
|
||||
|
||||
shallow pragma
|
||||
--------------
|
||||
The ``shallow`` pragma affects the semantics of a type: The compiler is
|
||||
allowed to make a shallow copy. This can cause serious semantic issues and
|
||||
break memory safety! However, it can speed up assignments considerably,
|
||||
because the semantics of Nim require deep copying of sequences and strings.
|
||||
This can be expensive, especially if sequences are used to build a tree
|
||||
structure:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
TNodeKind = enum nkLeaf, nkInner
|
||||
TNode {.final, shallow.} = object
|
||||
case kind: TNodeKind
|
||||
of nkLeaf:
|
||||
strVal: string
|
||||
of nkInner:
|
||||
children: seq[TNode]
|
||||
|
||||
|
||||
pure pragma
|
||||
-----------
|
||||
An object type can be marked with the ``pure`` pragma so that its type
|
||||
field which is used for runtime type identification is omitted. This used to be
|
||||
necessary for binary compatibility with other compiled languages.
|
||||
|
||||
An enum type can be marked as ``pure``. Then access of its fields always
|
||||
requires full qualification.
|
||||
|
||||
|
||||
asmNoStackFrame pragma
|
||||
----------------------
|
||||
A proc can be marked with the ``AsmNoStackFrame`` pragma to tell the compiler
|
||||
it should not generate a stack frame for the proc. There are also no exit
|
||||
statements like ``return result;`` generated and the generated C function is
|
||||
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
|
||||
the used C compiler).
|
||||
|
||||
**Note**: This pragma should only be used by procs which consist solely of
|
||||
assembler statements.
|
||||
|
||||
error pragma
|
||||
------------
|
||||
The ``error`` pragma is used to make the compiler output an error message
|
||||
with the given content. Compilation does not necessarily abort after an error
|
||||
though.
|
||||
|
||||
The ``error`` pragma can also be used to
|
||||
annotate a symbol (like an iterator or proc). The *usage* of the symbol then
|
||||
triggers a compile-time error. This is especially useful to rule out that some
|
||||
operation is valid due to overloading and type conversions:
|
||||
|
||||
.. code-block:: nim
|
||||
## check that underlying int values are compared and not the pointers:
|
||||
proc `==`(x, y: ptr int): bool {.error.}
|
||||
|
||||
|
||||
fatal pragma
|
||||
------------
|
||||
The ``fatal`` pragma is used to make the compiler output an error message
|
||||
with the given content. In contrast to the ``error`` pragma, compilation
|
||||
is guaranteed to be aborted by this pragma. Example:
|
||||
|
||||
.. code-block:: nim
|
||||
when not defined(objc):
|
||||
{.fatal: "Compile this program with the objc command!".}
|
||||
|
||||
warning pragma
|
||||
--------------
|
||||
The ``warning`` pragma is used to make the compiler output a warning message
|
||||
with the given content. Compilation continues after the warning.
|
||||
|
||||
hint pragma
|
||||
-----------
|
||||
The ``hint`` pragma is used to make the compiler output a hint message with
|
||||
the given content. Compilation continues after the hint.
|
||||
|
||||
line pragma
|
||||
-----------
|
||||
The ``line`` pragma can be used to affect line information of the annotated
|
||||
statement as seen in stack backtraces:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
template myassert*(cond: expr, msg = "") =
|
||||
if not cond:
|
||||
# change run-time line information of the 'raise' statement:
|
||||
{.line: InstantiationInfo().}:
|
||||
raise newException(EAssertionFailed, msg)
|
||||
|
||||
If the ``line`` pragma is used with a parameter, the parameter needs be a
|
||||
``tuple[filename: string, line: int]``. If it is used without a parameter,
|
||||
``system.InstantiationInfo()`` is used.
|
||||
|
||||
|
||||
linearScanEnd pragma
|
||||
--------------------
|
||||
The ``linearScanEnd`` pragma can be used to tell the compiler how to
|
||||
compile a Nim `case`:idx: statement. Syntactically it has to be used as a
|
||||
statement:
|
||||
|
||||
.. code-block:: nim
|
||||
case myInt
|
||||
of 0:
|
||||
echo "most common case"
|
||||
of 1:
|
||||
{.linearScanEnd.}
|
||||
echo "second most common case"
|
||||
of 2: echo "unlikely: use branch table"
|
||||
else: echo "unlikely too: use branch table for ", myInt
|
||||
|
||||
In the example, the case branches ``0`` and ``1`` are much more common than
|
||||
the other cases. Therefore the generated assembler code should test for these
|
||||
values first, so that the CPU's branch predictor has a good chance to succeed
|
||||
(avoiding an expensive CPU pipeline stall). The other cases might be put into a
|
||||
jump table for O(1) overhead, but at the cost of a (very likely) pipeline
|
||||
stall.
|
||||
|
||||
The ``linearScanEnd`` pragma should be put into the last branch that should be
|
||||
tested against via linear scanning. If put into the last branch of the
|
||||
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
|
||||
|
||||
|
||||
computedGoto pragma
|
||||
-------------------
|
||||
The ``computedGoto`` pragma can be used to tell the compiler how to
|
||||
compile a Nim `case`:idx: in a ``while true`` statement.
|
||||
Syntactically it has to be used as a statement inside the loop:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
MyEnum = enum
|
||||
enumA, enumB, enumC, enumD, enumE
|
||||
|
||||
proc vm() =
|
||||
var instructions: array [0..100, MyEnum]
|
||||
instructions[2] = enumC
|
||||
instructions[3] = enumD
|
||||
instructions[4] = enumA
|
||||
instructions[5] = enumD
|
||||
instructions[6] = enumC
|
||||
instructions[7] = enumA
|
||||
instructions[8] = enumB
|
||||
|
||||
instructions[12] = enumE
|
||||
var pc = 0
|
||||
while true:
|
||||
{.computedGoto.}
|
||||
let instr = instructions[pc]
|
||||
case instr
|
||||
of enumA:
|
||||
echo "yeah A"
|
||||
of enumC, enumD:
|
||||
echo "yeah CD"
|
||||
of enumB:
|
||||
echo "yeah B"
|
||||
of enumE:
|
||||
break
|
||||
inc(pc)
|
||||
|
||||
vm()
|
||||
|
||||
As the example shows ``computedGoto`` is mostly useful for interpreters. If
|
||||
the underlying backend (C compiler) does not support the computed goto
|
||||
extension the pragma is simply ignored.
|
||||
|
||||
|
||||
unroll pragma
|
||||
-------------
|
||||
The ``unroll`` pragma can be used to tell the compiler that it should unroll
|
||||
a `for`:idx: or `while`:idx: loop for runtime efficiency:
|
||||
|
||||
.. code-block:: nim
|
||||
proc searchChar(s: string, c: char): int =
|
||||
for i in 0 .. s.high:
|
||||
{.unroll: 4.}
|
||||
if s[i] == c: return i
|
||||
result = -1
|
||||
|
||||
In the above example, the search loop is unrolled by a factor 4. The unroll
|
||||
factor can be left out too; the compiler then chooses an appropriate unroll
|
||||
factor.
|
||||
|
||||
**Note**: Currently the compiler recognizes but ignores this pragma.
|
||||
|
||||
|
||||
immediate pragma
|
||||
----------------
|
||||
|
||||
See `Ordinary vs immediate templates`_.
|
||||
|
||||
|
||||
compilation option pragmas
|
||||
--------------------------
|
||||
The listed pragmas here can be used to override the code generation options
|
||||
for a proc/method/converter.
|
||||
|
||||
The implementation currently provides the following possible options (various
|
||||
others may be added later).
|
||||
|
||||
=============== =============== ============================================
|
||||
pragma allowed values description
|
||||
=============== =============== ============================================
|
||||
checks on|off Turns the code generation for all runtime
|
||||
checks on or off.
|
||||
boundChecks on|off Turns the code generation for array bound
|
||||
checks on or off.
|
||||
overflowChecks on|off Turns the code generation for over- or
|
||||
underflow checks on or off.
|
||||
nilChecks on|off Turns the code generation for nil pointer
|
||||
checks on or off.
|
||||
assertions on|off Turns the code generation for assertions
|
||||
on or off.
|
||||
warnings on|off Turns the warning messages of the compiler
|
||||
on or off.
|
||||
hints on|off Turns the hint messages of the compiler
|
||||
on or off.
|
||||
optimization none|speed|size Optimize the code for speed or size, or
|
||||
disable optimization.
|
||||
patterns on|off Turns the term rewriting templates/macros
|
||||
on or off.
|
||||
callconv cdecl|... Specifies the default calling convention for
|
||||
all procedures (and procedure types) that
|
||||
follow.
|
||||
=============== =============== ============================================
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
{.checks: off, optimization: speed.}
|
||||
# compile without runtime checks and optimize for speed
|
||||
|
||||
|
||||
push and pop pragmas
|
||||
--------------------
|
||||
The `push/pop`:idx: pragmas are very similar to the option directive,
|
||||
but are used to override the settings temporarily. Example:
|
||||
|
||||
.. code-block:: nim
|
||||
{.push checks: off.}
|
||||
# compile this section without runtime checks as it is
|
||||
# speed critical
|
||||
# ... some code ...
|
||||
{.pop.} # restore old settings
|
||||
|
||||
|
||||
register pragma
|
||||
---------------
|
||||
The ``register`` pragma is for variables only. It declares the variable as
|
||||
``register``, giving the compiler a hint that the variable should be placed
|
||||
in a hardware register for faster access. C compilers usually ignore this
|
||||
though and for good reasons: Often they do a better job without it anyway.
|
||||
|
||||
In highly specific cases (a dispatch loop of an bytecode interpreter for
|
||||
example) it may provide benefits, though.
|
||||
|
||||
|
||||
global pragma
|
||||
-------------
|
||||
The ``global`` pragma can be applied to a variable within a proc to instruct
|
||||
the compiler to store it in a global location and initialize it once at program
|
||||
startup.
|
||||
|
||||
.. code-block:: nim
|
||||
proc isHexNumber(s: string): bool =
|
||||
var pattern {.global.} = re"[0-9a-fA-F]+"
|
||||
result = s.match(pattern)
|
||||
|
||||
When used within a generic proc, a separate unique global variable will be
|
||||
created for each instantiation of the proc. The order of initialization of
|
||||
the created global variables within a module is not defined, but all of them
|
||||
will be initialized after any top-level variables in their originating module
|
||||
and before any variable in a module that imports it.
|
||||
|
||||
deadCodeElim pragma
|
||||
-------------------
|
||||
The ``deadCodeElim`` pragma only applies to whole modules: It tells the
|
||||
compiler to activate (or deactivate) dead code elimination for the module the
|
||||
pragma appears in.
|
||||
|
||||
The ``--deadCodeElim:on`` command line switch has the same effect as marking
|
||||
every module with ``{.deadCodeElim:on}``. However, for some modules such as
|
||||
the GTK wrapper it makes sense to *always* turn on dead code elimination -
|
||||
no matter if it is globally active or not.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
|
||||
..
|
||||
NoForward pragma
|
||||
----------------
|
||||
The ``noforward`` pragma can be used to turn on and off a special compilation
|
||||
mode that to large extent eliminates the need for forward declarations. In this
|
||||
mode, the proc definitions may appear out of order and the compiler will postpone
|
||||
their semantic analysis and compilation until it actually needs to generate code
|
||||
using the definitions. In this regard, this mode is similar to the modus operandi
|
||||
of dynamic scripting languages, where the function calls are not resolved until
|
||||
the code is executed. Here is the detailed algorithm taken by the compiler:
|
||||
|
||||
1. When a callable symbol is first encountered, the compiler will only note the
|
||||
symbol callable name and it will add it to the appropriate overload set in the
|
||||
current scope. At this step, it won't try to resolve any of the type expressions
|
||||
used in the signature of the symbol (so they can refer to other not yet defined
|
||||
symbols).
|
||||
|
||||
2. When a top level call is encountered (usually at the very end of the module),
|
||||
the compiler will try to determine the actual types of all of the symbols in the
|
||||
matching overload set. This is a potentially recursive process as the signatures
|
||||
of the symbols may include other call expressions, whoose types will be resolved
|
||||
at this point too.
|
||||
|
||||
3. Finally, after the best overload is picked, the compiler will start compiling
|
||||
the body of the respective symbol. This in turn will lead the compiler to discover
|
||||
more call expresions that need to be resolved and steps 2 and 3 will be repeated
|
||||
as necessary.
|
||||
|
||||
Please note that if a callable symbol is never used in this scenario, its body
|
||||
will never be compiled. This is the default behavior leading to best compilation
|
||||
times, but if exhaustive compilation of all definitions is required, using
|
||||
``nim check`` provides this option as well.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
{.noforward: on.}
|
||||
|
||||
proc foo(x: int) =
|
||||
bar x
|
||||
|
||||
proc bar(x: int) =
|
||||
echo x
|
||||
|
||||
foo(10)
|
||||
|
||||
|
||||
pragma pragma
|
||||
-------------
|
||||
|
||||
The ``pragma`` pragma can be used to declare user defined pragmas. This is
|
||||
useful because Nim's templates and macros do not affect pragmas. User
|
||||
defined pragmas are in a different module-wide scope than all other symbols.
|
||||
They cannot be imported from a module.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
when appType == "lib":
|
||||
{.pragma: rtl, exportc, dynlib, cdecl.}
|
||||
else:
|
||||
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
|
||||
|
||||
proc p*(a, b: int): int {.rtl.} =
|
||||
result = a+b
|
||||
|
||||
In the example a new pragma named ``rtl`` is introduced that either imports
|
||||
a symbol from a dynamic library or exports the symbol for dynamic library
|
||||
generation.
|
||||
|
||||
|
||||
Disabling certain messages
|
||||
--------------------------
|
||||
Nim generates some warnings and hints ("line too long") that may annoy the
|
||||
user. A mechanism for disabling certain messages is provided: Each hint
|
||||
and warning message contains a symbol in brackets. This is the message's
|
||||
identifier that can be used to enable or disable it:
|
||||
|
||||
.. code-block:: Nim
|
||||
{.hint[LineTooLong]: off.} # turn off the hint about too long lines
|
||||
|
||||
This is often better than disabling all warnings at once.
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue