515 lines
17 KiB
Text
515 lines
17 KiB
Text
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.
|
|
|
|
|
|
deprecated pragma
|
|
-----------------
|
|
|
|
The deprecated pragma is used to mark a symbol as deprecated:
|
|
|
|
.. code-block:: nimrod
|
|
proc p() {.deprecated.}
|
|
var x {.deprecated.}: char
|
|
|
|
It can also be used as a statement. Then it takes a list of *renamings*. The
|
|
upcoming ``nimfix`` tool can automatically update the code and perform these
|
|
renamings:
|
|
|
|
.. code-block:: nimrod
|
|
type
|
|
File = object
|
|
Stream = ref object
|
|
{.deprecated: [TFile: File, PStream: Stream].}
|
|
|
|
|
|
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.
|
|
|
|
|
|
experimental pragma
|
|
-------------------
|
|
|
|
The ``experimental`` pragma enables experimental language features. Depending
|
|
on the concrete feature this means that the feature is either considered
|
|
too unstable for an otherwise stable release or that the future of the feature
|
|
is uncertain (it may be removed any time).
|
|
|
|
Example:
|
|
|
|
.. code-block:: nim
|
|
{.experimental.}
|
|
|
|
proc useUsing(dest: var string) =
|
|
using dest
|
|
add "foo"
|
|
add "bar"
|
|
|