forked from nim-lang/Nim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
modules.txt
203 lines (144 loc) · 5.66 KB
/
modules.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
Modules
=======
Nim supports splitting a program into pieces by a module concept.
Each module needs to be in its own file and has its own `namespace`:idx:.
Modules enable `information hiding`:idx: and `separate compilation`:idx:.
A module may gain access to symbols of another module by the `import`:idx:
statement. `Recursive module dependencies`:idx: are allowed, but slightly
subtle. Only top-level symbols that are marked with an asterisk (``*``) are
exported. A valid module name can only be a valid Nim identifier (and thus its
filename is ``identifier.nim``).
The algorithm for compiling modules is:
- compile the whole module as usual, following import statements recursively
- if there is a cycle only import the already parsed symbols (that are
exported); if an unknown identifier occurs then abort
This is best illustrated by an example:
.. code-block:: nim
# Module A
type
T1* = int # Module A exports the type ``T1``
import B # the compiler starts parsing B
proc main() =
var i = p(3) # works because B has been parsed completely here
main()
.. code-block:: nim
# Module B
import A # A is not parsed here! Only the already known symbols
# of A are imported.
proc p*(x: A.T1): A.T1 =
# this works because the compiler has already
# added T1 to A's interface symbol table
result = x + 1
Import statement
~~~~~~~~~~~~~~~~
After the ``import`` statement a list of module names can follow or a single
module name followed by an ``except`` list to prevent some symbols to be
imported:
.. code-block:: nim
import strutils except `%`, toUpper
# doesn't work then:
echo "$1" % "abc".toUpper
It is not checked that the ``except`` list is really exported from the module.
This feature allows to compile against an older version of the module that
does not export these identifiers.
Include statement
~~~~~~~~~~~~~~~~~
The ``include`` statement does something fundamentally different than
importing a module: it merely includes the contents of a file. The ``include``
statement is useful to split up a large module into several files:
.. code-block:: nim
include fileA, fileB, fileC
Module names in imports
~~~~~~~~~~~~~~~~~~~~~~~
A module alias can be introduced via the ``as`` keyword:
.. code-block:: nim
import strutils as su, sequtils as qu
echo su.format("$1", "lalelu")
The original module name is then not accessible. The
notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"``
can be used to refer to a module in subdirectories:
.. code-block:: nim
import lib.pure.strutils, lib/pure/os, "lib/pure/times"
Note that the module name is still ``strutils`` and not ``lib.pure.strutils``
and so one **cannot** do:
.. code-block:: nim
import lib.pure.strutils
echo lib.pure.strutils
Likewise the following does not make sense as the name is ``strutils`` already:
.. code-block:: nim
import lib.pure.strutils as strutils
From import statement
~~~~~~~~~~~~~~~~~~~~~
After the ``from`` statement a module name follows followed by
an ``import`` to list the symbols one likes to use without explict
full qualification:
.. code-block:: nim
from strutils import `%`
echo "$1" % "abc"
# always possible: full qualification:
echo strutils.replace("abc", "a", "z")
It's also possible to use ``from module import nil`` if one wants to import
the module but wants to enforce fully qualified access to every symbol
in ``module``.
Export statement
~~~~~~~~~~~~~~~~
An ``export`` statement can be used for symbol fowarding so that client
modules don't need to import a module's dependencies:
.. code-block:: nim
# module B
type MyObject* = object
.. code-block:: nim
# module A
import B
export B.MyObject
proc `$`*(x: MyObject): string = "my object"
.. code-block:: nim
# module C
import A
# B.MyObject has been imported implicitly here:
var x: MyObject
echo($x)
Scope rules
-----------
Identifiers are valid from the point of their declaration until the end of
the block in which the declaration occurred. The range where the identifier
is known is the scope of the identifier. The exact scope of an
identifier depends on the way it was declared.
Block scope
~~~~~~~~~~~
The *scope* of a variable declared in the declaration part of a block
is valid from the point of declaration until the end of the block. If a
block contains a second block, in which the identifier is redeclared,
then inside this block, the second declaration will be valid. Upon
leaving the inner block, the first declaration is valid again. An
identifier cannot be redefined in the same block, except if valid for
procedure or iterator overloading purposes.
Tuple or object scope
~~~~~~~~~~~~~~~~~~~~~
The field identifiers inside a tuple or object definition are valid in the
following places:
* To the end of the tuple/object definition.
* Field designators of a variable of the given tuple/object type.
* In all descendant types of the object type.
Module scope
~~~~~~~~~~~~
All identifiers of a module are valid from the point of declaration until
the end of the module. Identifiers from indirectly dependent modules are *not*
available. The `system`:idx: module is automatically imported in every other
module.
If a module imports an identifier by two different modules, each occurrence of
the identifier has to be qualified, unless it is an overloaded procedure or
iterator in which case the overloading resolution takes place:
.. code-block:: nim
# Module A
var x*: string
.. code-block:: nim
# Module B
var x*: int
.. code-block:: nim
# Module C
import A, B
write(stdout, x) # error: x is ambiguous
write(stdout, A.x) # no error: qualifier used
var x = 4
write(stdout, x) # not ambiguous: uses the module C's x