First pass at compile-time/runtime terminology changes.
This commit is contained in:
parent
c2e6fc0dfb
commit
6bae78f365
1 changed files with 216 additions and 110 deletions
326
doc/manual.rst
326
doc/manual.rst
|
|
@ -46,7 +46,7 @@ and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
|
||||||
|
|
||||||
arrayConstructor = '[' expr ^* ',' ']'
|
arrayConstructor = '[' expr ^* ',' ']'
|
||||||
|
|
||||||
Other parts of Nim - like scoping rules or runtime semantics are only
|
Other parts of Nim - like scoping rules or execution semantics are only
|
||||||
described in the, more easily comprehensible, informal manner for now.
|
described in the, more easily comprehensible, informal manner for now.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ described in the, more easily comprehensible, informal manner for now.
|
||||||
Definitions
|
Definitions
|
||||||
===========
|
===========
|
||||||
|
|
||||||
A Nim program specifies a computation that acts on a memory consisting of
|
Nim code specifies a computation that acts on a memory consisting of
|
||||||
components called `locations`:idx:. A variable is basically a name for a
|
components called `locations`:idx:. A variable is basically a name for a
|
||||||
location. Each variable and location is of a certain `type`:idx:. The
|
location. Each variable and location is of a certain `type`:idx:. The
|
||||||
variable's type is called `static type`:idx:, the location's type is called
|
variable's type is called `static type`:idx:, the location's type is called
|
||||||
|
|
@ -71,21 +71,37 @@ identifier is declared unless overloading resolution rules suggest otherwise.
|
||||||
An expression specifies a computation that produces a value or location.
|
An expression specifies a computation that produces a value or location.
|
||||||
Expressions that produce locations are called `l-values`:idx:. An l-value
|
Expressions that produce locations are called `l-values`:idx:. An l-value
|
||||||
can denote either a location or the value the location contains, depending on
|
can denote either a location or the value the location contains, depending on
|
||||||
the context. Expressions whose values can be determined statically are called
|
the context.
|
||||||
`constant expressions`:idx:; they are never l-values.
|
|
||||||
|
|
||||||
A `static error`:idx: is an error that the implementation detects before
|
A Nim `program`:idx: consists of one or more text `source files`:idx: containing
|
||||||
program execution. Unless explicitly classified, an error is a static error.
|
Nim code. It is processed by a Nim `compiler`:idx: into an `executable`:idx:.
|
||||||
|
The nature of this executable depends on the compiler implementation; it may,
|
||||||
|
for example, be a native binary or JavaScript source code. A Nim program can
|
||||||
|
contain Nim code that will be executed at `compile time`:idx:, such as constant
|
||||||
|
expressions, macro definitions, and Nim procedures used by macro definitions.
|
||||||
|
Typically, the bulk of a Nim program's code is compiled into the executable and
|
||||||
|
executed at `runtime`:idx:. Only a subset of the Nim language is supported at
|
||||||
|
compile time, but it is a substantial subset. See `Restrictions on
|
||||||
|
Compile-Time Execution <restrictions-on-compile-time-execution>`_ for details.
|
||||||
|
|
||||||
A `checked runtime error`:idx: is an error that the implementation detects
|
The compiler parses Nim source code into an internal data structure called the
|
||||||
and reports at runtime. The method for reporting such errors is via *raising
|
`abstract syntax tree`:idx: (`AST`:idx). Then, before executing the code or
|
||||||
exceptions* or *dying with a fatal error*. However, the implementation
|
processing it into the executable, it transforms the AST through `semantic
|
||||||
provides a means to disable these runtime checks. See the section pragmas_
|
analysis`:idx:. This adds considerable semantic information to the AST, such as
|
||||||
for details.
|
expression types, identifier meanings, and in some cases expression values. An
|
||||||
|
error detected during semantic analysis is called a `static error`:idx:. Errors
|
||||||
|
mentioned in this manual are static errors when not otherwise specified.
|
||||||
|
|
||||||
Whether a checked runtime error results in an exception or in a fatal error at
|
An error detected during code execution (whether at compile time or at runtime)
|
||||||
runtime is implementation specific. Thus the following program is always
|
is a `checked execution error`:idx:. The method for reporting such errors is via
|
||||||
invalid:
|
*raising exceptions* or *dying with a fatal error*. However, the implementation
|
||||||
|
provides a means to disable these `execution-time checks`:idx:. See the section
|
||||||
|
pragmas_ for details.
|
||||||
|
|
||||||
|
Whether a checked execution error results in an exception or in a fatal error
|
||||||
|
is implementation specific. Thus the following program is invalid; even
|
||||||
|
though it purports to catch the `IndexError` from an out-of-bounds array access,
|
||||||
|
the compiler may instead choose to allow execution to die with a fatal error.
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
var a: array[0..1, char]
|
var a: array[0..1, char]
|
||||||
|
|
@ -95,11 +111,28 @@ invalid:
|
||||||
except IndexError:
|
except IndexError:
|
||||||
echo "invalid index"
|
echo "invalid index"
|
||||||
|
|
||||||
An `unchecked runtime error`:idx: is an error that is not guaranteed to be
|
An `unchecked execution error`:idx: is an error that is not guaranteed to be
|
||||||
detected, and can cause the subsequent behavior of the computation to
|
detected, and can cause the subsequent behavior of the computation to
|
||||||
be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:
|
be arbitrary. Unchecked execution errors cannot occur if only `safe`:idx:
|
||||||
language features are used.
|
language features are used and if no execution-time checks are disabled.
|
||||||
|
|
||||||
|
A `constant expression`:idx: is an expression whose value can be computed during
|
||||||
|
semantic analysis of the code in which it appears. It is never an l-value and
|
||||||
|
never has side effects. Constant expressions are not limited to the capabilities
|
||||||
|
of semantic analysis, such as constant folding; they can use the substantial
|
||||||
|
subset of the Nim language that is supported at compile time. Since constant
|
||||||
|
expressions can be used as an input to semantic analysis (such as for defining
|
||||||
|
array bounds), this flexibility requires the compiler to interleave semantic
|
||||||
|
analysis and compile-time code execution.
|
||||||
|
|
||||||
|
It is mostly accurate to picture semantic analysis proceeding top to bottom and
|
||||||
|
left to right in the source code, with compile-time code execution interleaved
|
||||||
|
when necessary to compute values that are required for subsequent semantic
|
||||||
|
analysis. We saw just above that this interleaving is necessary for handling
|
||||||
|
constant expressions. We will see much later in this document that macro
|
||||||
|
invocation not only requires this interleaving, but also creates a situation
|
||||||
|
where semantic analyis does not entirely proceed top to bottom and left to
|
||||||
|
right.
|
||||||
|
|
||||||
|
|
||||||
Lexical Analysis
|
Lexical Analysis
|
||||||
|
|
@ -673,10 +706,90 @@ Rationale: Consistency with overloaded assignment or assignment-like operations,
|
||||||
``a = b`` can be read as ``performSomeCopy(a, b)``.
|
``a = b`` can be read as ``performSomeCopy(a, b)``.
|
||||||
|
|
||||||
|
|
||||||
|
Constants and Constant Expressions
|
||||||
|
==================================
|
||||||
|
|
||||||
|
A `constant`:idx: is a symbol that is bound to the value of a `constant
|
||||||
|
expression`. This is an expression whose value can be computed during
|
||||||
|
semantic analysis of the code in which it appears. However, constant
|
||||||
|
expressions are not limited to the capabilities of semantic analysis; they
|
||||||
|
can use the substantial subset of the Nim language that is supported for
|
||||||
|
compile-time execution. Compile-time execution is interleaved with semantic
|
||||||
|
analysis as necessary. A constant's value cannot change after it is first
|
||||||
|
computed.
|
||||||
|
|
||||||
|
A constant expression must be composed of the following elements:
|
||||||
|
|
||||||
|
* literals
|
||||||
|
* previously declared constants and compile-time variables
|
||||||
|
* previously declared macros and templates
|
||||||
|
* previously declared procedures that have no side effects beyond
|
||||||
|
possibly modifying compile-time variables
|
||||||
|
* operators representing such procedures
|
||||||
|
* code blocks that can internally use all Nim features supported at
|
||||||
|
compile time (the next section below), but that cannot
|
||||||
|
refer to any external values beyond those listed above
|
||||||
|
|
||||||
|
Constant expressions must adhere to the restrictions on compile-time
|
||||||
|
execution described in `Restrictions on
|
||||||
|
Compile-Time Execution <restrictions-on-compile-time-execution>`_.
|
||||||
|
|
||||||
|
For example, the following code echoes the beginning of the Fibonacci
|
||||||
|
series **at compile time**. This is a demonstration of flexibility in
|
||||||
|
defining constants, not a recommended style for solving this problem!
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
:test: "nim c $1"
|
||||||
|
import strformat
|
||||||
|
|
||||||
|
var fib_n {.compileTime.}: int
|
||||||
|
var fib_prev {.compileTime.}: int
|
||||||
|
var fib_prev_prev {.compileTime.}: int
|
||||||
|
|
||||||
|
proc next_fib(): int =
|
||||||
|
result = if fib_n < 2:
|
||||||
|
fib_n
|
||||||
|
else:
|
||||||
|
fib_prev_prev + fib_prev
|
||||||
|
inc(fib_n)
|
||||||
|
fib_prev_prev = fib_prev
|
||||||
|
fib_prev = result
|
||||||
|
|
||||||
|
const f0 = next_fib()
|
||||||
|
const f1 = next_fib()
|
||||||
|
|
||||||
|
const display_fib = block:
|
||||||
|
const f2 = next_fib()
|
||||||
|
var result = fmt"Fibonacci sequence: {f0}, {f1}, {f2}, "
|
||||||
|
for i in 0..10:
|
||||||
|
if i > 0:
|
||||||
|
add(result, ", ")
|
||||||
|
add(result, $next_fib())
|
||||||
|
result
|
||||||
|
|
||||||
|
static:
|
||||||
|
echo display_fib
|
||||||
|
|
||||||
|
|
||||||
|
Restrictions on Compile-Time Execution
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Nim code that will be executed at compile-time cannot use the following
|
||||||
|
language features:
|
||||||
|
|
||||||
|
* methods
|
||||||
|
* closure iterators
|
||||||
|
* ``cast``
|
||||||
|
* ``ptr``s or ``ref``s
|
||||||
|
* the FFI
|
||||||
|
|
||||||
|
Some or all of these restrictions are likely to be lifted over time.
|
||||||
|
|
||||||
|
|
||||||
Types
|
Types
|
||||||
=====
|
=====
|
||||||
|
|
||||||
All expressions have a type which is known at compile time. Nim
|
All expressions have a type which is known during semantic analysis. Nim
|
||||||
is statically typed. One can declare new types, which is in essence defining
|
is statically typed. One can declare new types, which is in essence defining
|
||||||
an identifier that can be used to denote this custom type.
|
an identifier that can be used to denote this custom type.
|
||||||
|
|
||||||
|
|
@ -700,9 +813,9 @@ Ordinal types have the following characteristics:
|
||||||
the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to
|
the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to
|
||||||
be defined.
|
be defined.
|
||||||
- Ordinal values have a smallest possible value. Trying to count further
|
- Ordinal values have a smallest possible value. Trying to count further
|
||||||
down than the smallest value gives a checked runtime or static error.
|
down than the smallest value gives a checked execution or static error.
|
||||||
- Ordinal values have a largest possible value. Trying to count further
|
- Ordinal values have a largest possible value. Trying to count further
|
||||||
than the largest value gives a checked runtime or static error.
|
than the largest value gives a checked execution or static error.
|
||||||
|
|
||||||
Integers, bool, characters and enumeration types (and subranges of these
|
Integers, bool, characters and enumeration types (and subranges of these
|
||||||
types) belong to ordinal types. For reasons of simplicity of implementation
|
types) belong to ordinal types. For reasons of simplicity of implementation
|
||||||
|
|
@ -810,7 +923,7 @@ lowest and highest value of the type:
|
||||||
to 5. ``PositiveFloat`` defines a subrange of all positive floating point values.
|
to 5. ``PositiveFloat`` defines a subrange of all positive floating point values.
|
||||||
NaN does not belong to any subrange of floating point types.
|
NaN does not belong to any subrange of floating point types.
|
||||||
Assigning any other value to a variable of type ``Subrange`` is a
|
Assigning any other value to a variable of type ``Subrange`` is a
|
||||||
checked runtime error (or static error if it can be statically
|
checked execution error (or static error if it can be statically
|
||||||
determined). Assignments from the base type to one of its subrange types
|
determined). Assignments from the base type to one of its subrange types
|
||||||
(and vice versa) are allowed.
|
(and vice versa) are allowed.
|
||||||
|
|
||||||
|
|
@ -854,7 +967,7 @@ The IEEE standard defines five types of floating-point exceptions:
|
||||||
* Inexact: operation produces a result that cannot be represented with infinite
|
* Inexact: operation produces a result that cannot be represented with infinite
|
||||||
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
|
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
|
||||||
|
|
||||||
The IEEE exceptions are either ignored at runtime or mapped to the
|
The IEEE exceptions are either ignored during execution or mapped to the
|
||||||
Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
|
Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
|
||||||
`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
|
`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
|
||||||
and `FloatInexactError`:idx:.
|
and `FloatInexactError`:idx:.
|
||||||
|
|
@ -881,8 +994,9 @@ The only operations that are affected by the ``floatChecks`` pragma are
|
||||||
the ``+``, ``-``, ``*``, ``/`` operators for floating point types.
|
the ``+``, ``-``, ``*``, ``/`` operators for floating point types.
|
||||||
|
|
||||||
An implementation should always use the maximum precision available to evaluate
|
An implementation should always use the maximum precision available to evaluate
|
||||||
floating pointer values at compile time; this means expressions like
|
floating pointer values during semantic analysis; this means expressions like
|
||||||
``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` are true.
|
``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` that are evaluating during
|
||||||
|
constant folding are true.
|
||||||
|
|
||||||
|
|
||||||
Boolean type
|
Boolean type
|
||||||
|
|
@ -1110,8 +1224,8 @@ tuples, objects and sets belong to the structured types.
|
||||||
Array and sequence types
|
Array and sequence types
|
||||||
------------------------
|
------------------------
|
||||||
Arrays are a homogeneous type, meaning that each element in the array
|
Arrays are a homogeneous type, meaning that each element in the array
|
||||||
has the same type. Arrays always have a fixed length which is specified at
|
has the same type. Arrays always have a fixed length which is known during
|
||||||
compile time (except for open arrays). They can be indexed by any ordinal type.
|
semantic analysis (except for open arrays). They can be indexed by any ordinal type.
|
||||||
A parameter ``A`` may be an *open array*, in which case it is indexed by
|
A parameter ``A`` may be an *open array*, in which case it is indexed by
|
||||||
integers from 0 to ``len(A)-1``. An array expression may be constructed by the
|
integers from 0 to ``len(A)-1``. An array expression may be constructed by the
|
||||||
array constructor ``[]``. The element type of this array expression is
|
array constructor ``[]``. The element type of this array expression is
|
||||||
|
|
@ -1119,7 +1233,7 @@ inferred from the type of the first element. All other elements need to be
|
||||||
implicitly convertable to this type.
|
implicitly convertable to this type.
|
||||||
|
|
||||||
Sequences are similar to arrays but of dynamic length which may change
|
Sequences are similar to arrays but of dynamic length which may change
|
||||||
during runtime (like strings). Sequences are implemented as growable arrays,
|
during execution (like strings). Sequences are implemented as growable arrays,
|
||||||
allocating pieces of memory as items are added. A sequence ``S`` is always
|
allocating pieces of memory as items are added. A sequence ``S`` is always
|
||||||
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
|
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
|
||||||
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
||||||
|
|
@ -1153,7 +1267,7 @@ operator, and remove (and get) the last element of a sequence with the
|
||||||
|
|
||||||
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
The notation ``x[i]`` can be used to access the i-th element of ``x``.
|
||||||
|
|
||||||
Arrays are always bounds checked (at compile-time or at runtime). These
|
Arrays are always bounds checked (statically or during execution). These
|
||||||
checks can be disabled via pragmas or invoking the compiler with the
|
checks can be disabled via pragmas or invoking the compiler with the
|
||||||
``--boundChecks:off`` command line switch.
|
``--boundChecks:off`` command line switch.
|
||||||
|
|
||||||
|
|
@ -1260,7 +1374,7 @@ is currently not checked.
|
||||||
|
|
||||||
**Future directions**: GC'ed memory should be allowed in unchecked arrays and
|
**Future directions**: GC'ed memory should be allowed in unchecked arrays and
|
||||||
there should be an explicit annotation of how the GC is to determine the
|
there should be an explicit annotation of how the GC is to determine the
|
||||||
runtime size of the array.
|
execution-time size of the array.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1317,7 +1431,7 @@ can also be defined with indentation instead of ``[]``:
|
||||||
age: natural # and an age
|
age: natural # and an age
|
||||||
|
|
||||||
Objects provide many features that tuples do not. Object provide inheritance
|
Objects provide many features that tuples do not. Object provide inheritance
|
||||||
and information hiding. Objects have access to their type at runtime, so that
|
and information hiding. Objects have access to their type during execution, so that
|
||||||
the ``of`` operator can be used to determine the object's type. The ``of`` operator
|
the ``of`` operator can be used to determine the object's type. The ``of`` operator
|
||||||
is similar to the ``instanceof`` operator in Java.
|
is similar to the ``instanceof`` operator in Java.
|
||||||
|
|
||||||
|
|
@ -1415,7 +1529,7 @@ safety its address cannot be taken and assignments to it are restricted: The
|
||||||
new value must not lead to a change of the active object branch. For an object
|
new value must not lead to a change of the active object branch. For an object
|
||||||
branch switch ``system.reset`` has to be used. Also, when the fields of a
|
branch switch ``system.reset`` has to be used. Also, when the fields of a
|
||||||
particular branch are specified during object construction, the correct value
|
particular branch are specified during object construction, the correct value
|
||||||
for the discriminator must be supplied at compile-time.
|
for the discriminator must be available for semantic analysis.
|
||||||
|
|
||||||
Package level objects
|
Package level objects
|
||||||
---------------------
|
---------------------
|
||||||
|
|
@ -1429,7 +1543,7 @@ contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does
|
||||||
not yet know the size of the object. To complete an incomplete object
|
not yet know the size of the object. To complete an incomplete object
|
||||||
the ``package`` pragma has to be used. ``package`` implies ``byref``.
|
the ``package`` pragma has to be used. ``package`` implies ``byref``.
|
||||||
|
|
||||||
As long as a type ``T`` is incomplete ``sizeof(T)`` or "runtime type
|
As long as a type ``T`` is incomplete ``sizeof(T)`` or "execution-time type
|
||||||
information" for ``T`` is not available.
|
information" for ``T`` is not available.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1859,7 +1973,7 @@ that don't. Distinct types provide a means to introduce a new string type
|
||||||
username: string
|
username: string
|
||||||
|
|
||||||
db.query("SELECT FROM users WHERE name = '$1'" % username)
|
db.query("SELECT FROM users WHERE name = '$1'" % username)
|
||||||
# Error at compile time: `query` expects an SQL string!
|
# Static error: `query` expects an SQL string!
|
||||||
|
|
||||||
|
|
||||||
It is an essential property of abstract types that they **do not** imply a
|
It is an essential property of abstract types that they **do not** imply a
|
||||||
|
|
@ -2246,11 +2360,8 @@ Overloading resolution
|
||||||
======================
|
======================
|
||||||
|
|
||||||
In a call ``p(args)`` the routine ``p`` that matches best is selected. If
|
In a call ``p(args)`` the routine ``p`` that matches best is selected. If
|
||||||
multiple routines match equally well, the ambiguity is reported at compiletime.
|
multiple routines match equally well, the ambiguity is reported during
|
||||||
|
semantic analysis.
|
||||||
Every arg in args needs to match. There are multiple different categories how an
|
|
||||||
argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
|
|
||||||
of the argument.
|
|
||||||
|
|
||||||
1. Exact match: ``a`` and ``f`` are of the same type.
|
1. Exact match: ``a`` and ``f`` are of the same type.
|
||||||
2. Literal match: ``a`` is an integer literal of value ``v``
|
2. Literal match: ``a`` is an integer literal of value ``v``
|
||||||
|
|
@ -2627,53 +2738,36 @@ identifier ``_`` can be used to ignore some parts of the tuple:
|
||||||
Const section
|
Const section
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
`Constants`:idx: are symbols which are bound to a value. The constant's value
|
A const section declares constants whose values are constant expressions:
|
||||||
cannot change. The compiler must be able to evaluate the expression in a
|
|
||||||
constant declaration at compile time.
|
|
||||||
|
|
||||||
Nim contains a sophisticated compile-time evaluator, so procedures which
|
.. code-block::
|
||||||
have no side-effect can be used in constant expressions too:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
import strutils
|
import strutils
|
||||||
const
|
const
|
||||||
|
roundPi = 3.1415
|
||||||
constEval = contains("abc", 'b') # computed at compile time!
|
constEval = contains("abc", 'b') # computed at compile time!
|
||||||
|
|
||||||
|
Once declared, a constant's symbol can be used as a constant expression.
|
||||||
|
|
||||||
The rules for compile-time computability are:
|
See `Constants and Constant Expressions <#constants-and-constant-expressions>`_
|
||||||
|
for details.
|
||||||
1. Literals are compile-time computable.
|
|
||||||
2. Type conversions are compile-time computable.
|
|
||||||
3. Procedure calls of the form ``p(X)`` are compile-time computable if
|
|
||||||
``p`` is a proc without side-effects (see the `noSideEffect pragma
|
|
||||||
<#pragmas-nosideeffect-pragma>`_ for details) and if ``X`` is a
|
|
||||||
(possibly empty) list of compile-time computable arguments.
|
|
||||||
|
|
||||||
|
|
||||||
Constants cannot be of type ``ptr``, ``ref`` or ``var``, nor can
|
|
||||||
they contain such a type.
|
|
||||||
|
|
||||||
|
|
||||||
Static statement/expression
|
Static statement/expression
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
A static statement/expression can be used to enforce compile
|
A static statement/expression explicitly requires compile-time execution.
|
||||||
time evaluation explicitly. Enforced compile time evaluation can even evaluate
|
Even some code that has side effects is permitted in a static block:
|
||||||
code that has side effects:
|
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
static:
|
static:
|
||||||
echo "echo at compile time"
|
echo "echo at compile time"
|
||||||
|
|
||||||
It's a static error if the compiler cannot perform the evaluation at compile
|
There are limitations on what Nim code can be executed at compile time;
|
||||||
|
see `Restrictions on Compile-Time Execution
|
||||||
|
<#restrictions-on-compile-time-execution>`_ for details.
|
||||||
|
It's a static error if the compiler cannot execute the block at compile
|
||||||
time.
|
time.
|
||||||
|
|
||||||
The current implementation poses some restrictions for compile time
|
|
||||||
evaluation: Code which contains ``cast`` or makes use of the foreign function
|
|
||||||
interface cannot be evaluated at compile time. Later versions of Nim will
|
|
||||||
support the FFI at compile time.
|
|
||||||
|
|
||||||
|
|
||||||
If statement
|
If statement
|
||||||
------------
|
------------
|
||||||
|
|
@ -2747,9 +2841,9 @@ empty ``discard`` statement should be used.
|
||||||
For non ordinal types it is not possible to list every possible value and so
|
For non ordinal types it is not possible to list every possible value and so
|
||||||
these always require an ``else`` part.
|
these always require an ``else`` part.
|
||||||
|
|
||||||
As case statements perform compile-time exhaustiveness checks, the value in
|
Because case statements are checked for exhaustiveness during semantic analysis,
|
||||||
every ``of`` branch must be known at compile time. This fact is also exploited
|
the value in every ``of`` branch must be computable during analysis.
|
||||||
to generate more performant code.
|
This restriction also allows the compiler to generate more performant code.
|
||||||
|
|
||||||
As a special semantic extension, an expression in an ``of`` branch of a case
|
As a special semantic extension, an expression in an ``of`` branch of a case
|
||||||
statement may evaluate to a set or array constructor; the set or array is then
|
statement may evaluate to a set or array constructor; the set or array is then
|
||||||
|
|
@ -2814,10 +2908,10 @@ Example:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
proc someProcThatMayRunInCompileTime(): bool =
|
proc someProcThatMayRunInCompileTime(): bool =
|
||||||
when nimvm:
|
when nimvm:
|
||||||
# This code runs in compile time
|
# This code executes at compile time
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
# This code runs in runtime
|
# This code executes at runtime
|
||||||
result = false
|
result = false
|
||||||
const ctValue = someProcThatMayRunInCompileTime()
|
const ctValue = someProcThatMayRunInCompileTime()
|
||||||
let rtValue = someProcThatMayRunInCompileTime()
|
let rtValue = someProcThatMayRunInCompileTime()
|
||||||
|
|
@ -3557,7 +3651,7 @@ returned value is an l-value and can be modified by the caller:
|
||||||
writeAccessToG() = 6
|
writeAccessToG() = 6
|
||||||
assert g == 6
|
assert g == 6
|
||||||
|
|
||||||
It is a compile time error if the implicitly introduced pointer could be
|
It is a static error if the implicitly introduced pointer could be
|
||||||
used to access a location beyond its lifetime:
|
used to access a location beyond its lifetime:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -3673,7 +3767,7 @@ Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over
|
||||||
collide 1 because the resolution works from left to right.
|
collide 1 because the resolution works from left to right.
|
||||||
In the example ``Unit, Thing`` is preferred over ``Thing, Unit``.
|
In the example ``Unit, Thing`` is preferred over ``Thing, Unit``.
|
||||||
|
|
||||||
**Note**: Compile time evaluation is not (yet) supported for methods.
|
**Note**: Compile time execution is not (yet) supported for methods.
|
||||||
|
|
||||||
|
|
||||||
Inhibit dynamic method resolution via procCall
|
Inhibit dynamic method resolution via procCall
|
||||||
|
|
@ -3794,7 +3888,7 @@ In contrast to that, a `closure iterator`:idx: can be passed around more freely:
|
||||||
Closure iterators have other restrictions than inline iterators:
|
Closure iterators have other restrictions than inline iterators:
|
||||||
|
|
||||||
1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
|
1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
|
||||||
2. For now, a closure iterator cannot be evaluated at compile time.
|
2. For now, a closure iterator cannot be executed at compile time.
|
||||||
3. ``return`` is allowed in a closure iterator (but rarely useful) and ends
|
3. ``return`` is allowed in a closure iterator (but rarely useful) and ends
|
||||||
iteration.
|
iteration.
|
||||||
4. Neither inline nor closure iterators can be recursive.
|
4. Neither inline nor closure iterators can be recursive.
|
||||||
|
|
@ -4113,7 +4207,7 @@ The exception tree is defined in the `system <system.html>`_ module.
|
||||||
Every exception inherits from ``system.Exception``. Exceptions that indicate
|
Every exception inherits from ``system.Exception``. Exceptions that indicate
|
||||||
programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
|
programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
|
||||||
and are stricly speaking not catchable as they can also be mapped to an operation
|
and are stricly speaking not catchable as they can also be mapped to an operation
|
||||||
that terminates the whole process. Exceptions that indicate any other runtime error
|
that terminates the whole process. Exceptions that indicate any other execution error
|
||||||
that can be caught inherit from ``system.CatchableError``
|
that can be caught inherit from ``system.CatchableError``
|
||||||
(which is a subtype of ``Exception``).
|
(which is a subtype of ``Exception``).
|
||||||
|
|
||||||
|
|
@ -4351,7 +4445,7 @@ a `type variable`:idx:.
|
||||||
Is operator
|
Is operator
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The ``is`` operator checks for type equivalence at compile time. It is
|
The ``is`` operator checks for type equivalence during semantic analysis. It is
|
||||||
therefore very useful for type specialization within generic code:
|
therefore very useful for type specialization within generic code:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -5357,6 +5451,14 @@ invocation would have been replaced by its result in the source
|
||||||
code. This can be used to implement `domain specific
|
code. This can be used to implement `domain specific
|
||||||
languages`:idx:.
|
languages`:idx:.
|
||||||
|
|
||||||
|
Macro invocation leads to a case where semantic analyis does **not** entirely
|
||||||
|
proceed top to bottom and left to right. The compiler must
|
||||||
|
|
||||||
|
* perform semantic analysis through the end of the macro invocation,
|
||||||
|
* execute the macro body,
|
||||||
|
* replace the AST of the macro invocation with the AST returned by the macro,
|
||||||
|
* and finally repeat semantic analysis of that region of the code.
|
||||||
|
|
||||||
While macros enable advanced compile-time code transformations, they
|
While macros enable advanced compile-time code transformations, they
|
||||||
cannot change Nim's syntax. However, this is no real restriction because
|
cannot change Nim's syntax. However, this is no real restriction because
|
||||||
Nim's syntax is flexible enough anyway.
|
Nim's syntax is flexible enough anyway.
|
||||||
|
|
@ -5639,7 +5741,8 @@ static[T]
|
||||||
|
|
||||||
**Note**: static[T] is still in development.
|
**Note**: static[T] is still in development.
|
||||||
|
|
||||||
As their name suggests, static parameters must be known at compile-time:
|
As their name suggests, static parameters must be computable during
|
||||||
|
semantic analysis:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
||||||
|
|
@ -5651,7 +5754,8 @@ As their name suggests, static parameters must be known at compile-time:
|
||||||
# regex, stored in a global variable
|
# regex, stored in a global variable
|
||||||
|
|
||||||
precompiledRegex(paramStr(1)) # Error, command-line options
|
precompiledRegex(paramStr(1)) # Error, command-line options
|
||||||
# are not known at compile-time
|
# are not computable during
|
||||||
|
# semantic analysis
|
||||||
|
|
||||||
|
|
||||||
For the purposes of code generation, all static params are treated as
|
For the purposes of code generation, all static params are treated as
|
||||||
|
|
@ -5665,7 +5769,7 @@ Static params can also appear in the signatures of generic types:
|
||||||
type
|
type
|
||||||
Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T]
|
Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T]
|
||||||
# Note how `Number` is just a type constraint here, while
|
# Note how `Number` is just a type constraint here, while
|
||||||
# `static int` requires us to supply a compile-time int value
|
# `static int` requires us to supply an int value
|
||||||
|
|
||||||
AffineTransform2D[T] = Matrix[3, 3, T]
|
AffineTransform2D[T] = Matrix[3, 3, T]
|
||||||
AffineTransform3D[T] = Matrix[4, 4, T]
|
AffineTransform3D[T] = Matrix[4, 4, T]
|
||||||
|
|
@ -5673,13 +5777,12 @@ Static params can also appear in the signatures of generic types:
|
||||||
var m1: AffineTransform3D[float] # OK
|
var m1: AffineTransform3D[float] # OK
|
||||||
var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
|
var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
|
||||||
|
|
||||||
Please note that ``static T`` is just a syntactic convenience for the
|
Please note that ``static T`` is just a syntactic convenience for the underlying
|
||||||
underlying generic type ``static[T]``. The type param can be omitted
|
generic type ``static[T]``. The type param can be omitted to obtain the type
|
||||||
to obtain the type class of all values known at compile-time. A more
|
class of all values computable during semantic analysis. A more specific type
|
||||||
specific type class can be created by instantiating ``static`` with
|
class can be created by instantiating ``static`` with another type class.
|
||||||
another type class.
|
|
||||||
|
|
||||||
You can force the evaluation of a certain expression at compile-time by
|
You can force the evaluation of a certain expression during semantic analysis by
|
||||||
coercing it to a corresponding ``static`` type:
|
coercing it to a corresponding ``static`` type:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -6766,11 +6869,11 @@ pragma block can be used:
|
||||||
|
|
||||||
compileTime pragma
|
compileTime pragma
|
||||||
------------------
|
------------------
|
||||||
The ``compileTime`` pragma is used to mark a proc or variable to be used at
|
The ``compileTime`` pragma is used to mark a proc or variable to be used only
|
||||||
compile time only. No code will be generated for it. Compile time procs are
|
during compile-time execution. No code will be generated for it. Compile time
|
||||||
useful as helpers for macros. Since version 0.12.0 of the language, a proc
|
procs are useful as helpers for macros. Since version 0.12.0 of the language, a
|
||||||
that uses ``system.NimNode`` within its parameter types is implicitly declared
|
proc that uses ``system.NimNode`` within its parameter types is implicitly
|
||||||
``compileTime``:
|
declared ``compileTime``:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
proc astHelper(n: NimNode): NimNode =
|
proc astHelper(n: NimNode): NimNode =
|
||||||
|
|
@ -6858,7 +6961,7 @@ structure:
|
||||||
pure pragma
|
pure pragma
|
||||||
-----------
|
-----------
|
||||||
An object type can be marked with the ``pure`` pragma so that its type
|
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
|
field which is used for execution-time type identification is omitted. This used to be
|
||||||
necessary for binary compatibility with other compiled languages.
|
necessary for binary compatibility with other compiled languages.
|
||||||
|
|
||||||
An enum type can be marked as ``pure``. Then access of its fields always
|
An enum type can be marked as ``pure``. Then access of its fields always
|
||||||
|
|
@ -6884,7 +6987,7 @@ though.
|
||||||
|
|
||||||
The ``error`` pragma can also be used to
|
The ``error`` pragma can also be used to
|
||||||
annotate a symbol (like an iterator or proc). The *usage* of the symbol then
|
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
|
triggers a static error. This is especially useful to rule out that some
|
||||||
operation is valid due to overloading and type conversions:
|
operation is valid due to overloading and type conversions:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -7006,7 +7109,7 @@ extension the pragma is simply ignored.
|
||||||
unroll pragma
|
unroll pragma
|
||||||
-------------
|
-------------
|
||||||
The ``unroll`` pragma can be used to tell the compiler that it should unroll
|
The ``unroll`` pragma can be used to tell the compiler that it should unroll
|
||||||
a `for`:idx: or `while`:idx: loop for runtime efficiency:
|
a `for`:idx: or `while`:idx: loop for execution efficiency:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
proc searchChar(s: string, c: char): int =
|
proc searchChar(s: string, c: char): int =
|
||||||
|
|
@ -7039,7 +7142,7 @@ others may be added later).
|
||||||
=============== =============== ============================================
|
=============== =============== ============================================
|
||||||
pragma allowed values description
|
pragma allowed values description
|
||||||
=============== =============== ============================================
|
=============== =============== ============================================
|
||||||
checks on|off Turns the code generation for all runtime
|
checks on|off Turns the code generation for all execution
|
||||||
checks on or off.
|
checks on or off.
|
||||||
boundChecks on|off Turns the code generation for array bound
|
boundChecks on|off Turns the code generation for array bound
|
||||||
checks on or off.
|
checks on or off.
|
||||||
|
|
@ -7066,7 +7169,7 @@ Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
{.checks: off, optimization: speed.}
|
{.checks: off, optimization: speed.}
|
||||||
# compile without runtime checks and optimize for speed
|
# compile without execution-time checks and optimize for speed
|
||||||
|
|
||||||
|
|
||||||
push and pop pragmas
|
push and pop pragmas
|
||||||
|
|
@ -7076,7 +7179,7 @@ but are used to override the settings temporarily. Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
{.push checks: off.}
|
{.push checks: off.}
|
||||||
# compile this section without runtime checks as it is
|
# compile this section without execution-time checks as it is
|
||||||
# speed critical
|
# speed critical
|
||||||
# ... some code ...
|
# ... some code ...
|
||||||
{.pop.} # restore old settings
|
{.pop.} # restore old settings
|
||||||
|
|
@ -7321,7 +7424,8 @@ compiler like you would using the commandline switch ``--passC``:
|
||||||
{.passC: "-Wall -Werror".}
|
{.passC: "-Wall -Werror".}
|
||||||
|
|
||||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||||
embed parameters from an external command at compile time:
|
embed parameters from an external command that will be executed
|
||||||
|
during semantic analysis:
|
||||||
|
|
||||||
.. code-block:: Nim
|
.. code-block:: Nim
|
||||||
{.passC: gorge("pkg-config --cflags sdl").}
|
{.passC: gorge("pkg-config --cflags sdl").}
|
||||||
|
|
@ -7335,7 +7439,8 @@ like you would using the commandline switch ``--passL``:
|
||||||
{.passL: "-lSDLmain -lSDL".}
|
{.passL: "-lSDLmain -lSDL".}
|
||||||
|
|
||||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||||
embed parameters from an external command at compile time:
|
embed parameters from an external command that will be executed
|
||||||
|
during semantic analysis:
|
||||||
|
|
||||||
.. code-block:: Nim
|
.. code-block:: Nim
|
||||||
{.passL: gorge("pkg-config --libs sdl").}
|
{.passL: gorge("pkg-config --libs sdl").}
|
||||||
|
|
@ -7946,7 +8051,7 @@ interoperability with C. Combining packed pragma with inheritance is not
|
||||||
defined, and it should not be used with GC'ed memory (ref's).
|
defined, and it should not be used with GC'ed memory (ref's).
|
||||||
|
|
||||||
**Future directions**: Using GC'ed memory in packed pragma will result in
|
**Future directions**: Using GC'ed memory in packed pragma will result in
|
||||||
compile-time error. Usage with inheritance should be defined and documented.
|
a static error. Usage with inheritance should be defined and documented.
|
||||||
|
|
||||||
|
|
||||||
Dynlib pragma for import
|
Dynlib pragma for import
|
||||||
|
|
@ -8229,8 +8334,8 @@ Example:
|
||||||
|
|
||||||
The parallel statement is the preferred mechanism to introduce parallelism
|
The parallel statement is the preferred mechanism to introduce parallelism
|
||||||
in a Nim program. A subset of the Nim language is valid within a
|
in a Nim program. A subset of the Nim language is valid within a
|
||||||
``parallel`` section. This subset is checked to be free of data races at
|
``parallel`` section. This subset is checked to be free of data races during
|
||||||
compile time. A sophisticated `disjoint checker`:idx: ensures that no data
|
semantic analysis. A sophisticated `disjoint checker`:idx: ensures that no data
|
||||||
races are possible even though shared memory is extensively supported!
|
races are possible even though shared memory is extensively supported!
|
||||||
|
|
||||||
The subset is in fact the full language with the following
|
The subset is in fact the full language with the following
|
||||||
|
|
@ -8263,8 +8368,8 @@ pragmas:
|
||||||
1) A `guard`:idx: annotation is introduced to prevent data races.
|
1) A `guard`:idx: annotation is introduced to prevent data races.
|
||||||
2) Every access of a guarded memory location needs to happen in an
|
2) Every access of a guarded memory location needs to happen in an
|
||||||
appropriate `locks`:idx: statement.
|
appropriate `locks`:idx: statement.
|
||||||
3) Locks and routines can be annotated with `lock levels`:idx: to prevent
|
3) Locks and routines can be annotated with `lock levels`:idx: to allow
|
||||||
deadlocks at compile time.
|
potential deadlocks to be detected during static analysis.
|
||||||
|
|
||||||
|
|
||||||
Guards and the locks section
|
Guards and the locks section
|
||||||
|
|
@ -8296,9 +8401,9 @@ Top level accesses to ``gdata`` are always allowed so that it can be initialized
|
||||||
conveniently. It is *assumed* (but not enforced) that every top level statement
|
conveniently. It is *assumed* (but not enforced) that every top level statement
|
||||||
is executed before any concurrent action happens.
|
is executed before any concurrent action happens.
|
||||||
|
|
||||||
The ``locks`` section deliberately looks ugly because it has no runtime
|
The ``locks`` section deliberately looks ugly because it has no execution-time
|
||||||
semantics and should not be used directly! It should only be used in templates
|
semantics and should not be used directly! It should only be used in templates
|
||||||
that also implement some form of locking at runtime:
|
that also implement some form of locking during execution:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
template lock(a: TLock; body: untyped) =
|
template lock(a: TLock; body: untyped) =
|
||||||
|
|
@ -8384,9 +8489,10 @@ This means the following compiles (for now) even though it really should not:
|
||||||
Lock levels
|
Lock levels
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Lock levels are used to enforce a global locking order in order to prevent
|
Lock levels are used to enforce a global locking order in order to detect
|
||||||
deadlocks at compile-time. A lock level is an constant integer in the range
|
potential deadlocks during semantic analysis. A lock level is an constant
|
||||||
0..1_000. Lock level 0 means that no lock is acquired at all.
|
integer in the range 0..1_000. Lock level 0 means that no lock is acquired at
|
||||||
|
all.
|
||||||
|
|
||||||
If a section of code holds a lock of level ``M`` than it can also acquire any
|
If a section of code holds a lock of level ``M`` than it can also acquire any
|
||||||
lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks
|
lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks
|
||||||
|
|
@ -8416,7 +8522,7 @@ single ``locks`` section:
|
||||||
|
|
||||||
|
|
||||||
Here is how a typical multilock statement can be implemented in Nim. Note how
|
Here is how a typical multilock statement can be implemented in Nim. Note how
|
||||||
the runtime check is required to ensure a global ordering for two locks ``a``
|
the execution check is required to ensure a global ordering for two locks ``a``
|
||||||
and ``b`` of the same lock level:
|
and ``b`` of the same lock level:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue