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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
|
================================
NimScript
================================
Strictly speaking, ``NimScript`` is the subset of Nim that can be evaluated
by Nim's builtin virtual machine (VM). This VM is used for Nim's compiletime
function evaluation features.
The ``nim`` executable processes the ``.nims`` configuration files in
the following directories (in this order; later files overwrite
previous settings):
1) If environment variable ``XDG_CONFIG_HOME`` is defined,
``$XDG_CONFIG_HOME/nim/config.nims`` or
``~/.config/nim/config.nims`` (POSIX) or
``%APPDATA%/nim/config.nims`` (Windows). This file can be skipped
with the ``--skipUserCfg`` command line option.
2) ``$parentDir/config.nims`` where ``$parentDir`` stands for any
parent directory of the project file's path. These files can be
skipped with the ``--skipParentCfg`` command line option.
3) ``$projectDir/config.nims`` where ``$projectDir`` stands for the
project's path. This file can be skipped with the ``--skipProjCfg``
command line option.
4) A project can also have a project specific configuration file named
``$project.nims`` that resides in the same directory as
``$project.nim``. This file can be skipped with the same
``--skipProjCfg`` command line option.
For available procs and implementation details see `nimscript <nimscript.html>`_.
Limitations
===========
NimScript is subject to some limitations caused by the implementation of the VM
(virtual machine):
* Nim's FFI (foreign function interface) is not available in NimScript. This
means that any stdlib module which relies on ``importc`` can not be used in
the VM.
* ``ptr`` operations are are hard to emulate with the symbolic representation
the VM uses. They are available and tested extensively but there are bugs left.
* ``var T`` function arguments rely on ``ptr`` operations internally and might
also be problematic in some cases.
* More than one level of `ref` is generally not supported (for example, the type
`ref ref int`).
* Multimethods are not available.
* ``random.randomize()`` requires an ``int64`` explicitly passed as argument, you *must* pass a Seed integer.
* ``unicode`` can be imported, but not ``unidecode``.
Standard library modules
========================
At least the following standard library modules are available:
* `macros <macros.html>`_
* `os <os.html>`_
* `strutils <strutils.html>`_
* `math <math.html>`_
* `distros <distros.html>`_
* `sugar <sugar.html>`_
* `algorithm <algorithm.html>`_
* `base64 <base64.html>`_
* `bitops <bitops.html>`_
* `chains <chains.html>`_
* `colors <colors.html>`_
* `complex <complex.html>`_
* `htmlgen <htmlgen.html>`_
* `httpcore <httpcore.html>`_
* `lenientops <lenientops.html>`_
* `mersenne <mersenne.html>`_
* `options <options.html>`_
* `parseutils <parseutils.html>`_
* `punycode <punycode.html>`_
* `random <punycode.html>`_
* `stats <stats.html>`_
* `strformat <strformat.html>`_
* `strmisc <strmisc.html>`_
* `strscans <strscans.html>`_
* `unicode <unicode.html>`_
* `uri <uri.html>`_
* `std/editdistance <editdistance.html>`_
* `std/wordwrap <wordwrap.html>`_
* `std/sums <sums.html>`_
In addition to the standard Nim syntax (`system <system.html>`_ module),
NimScripts support the procs and templates defined in the
`nimscript <nimscript.html>`_ module too.
NimScript as a configuration file
=================================
A command-line switch ``--FOO`` is written as ``switch("FOO")`` in
NimScript. Similarly, command-line ``--FOO:VAL`` translates to
``switch("FOO", "VAL")``.
Here are few examples of using the ``switch`` proc:
.. code-block:: nim
# command-line: --opt:size
switch("opt", "size")
# command-line: --define:foo or -d:foo
switch("define", "foo")
# command-line: --forceBuild
switch("forceBuild")
NimScripts also support ``--`` templates for convenience, which look
like command-line switches written as-is in the NimScript file. So the
above example can be rewritten as:
.. code-block:: nim
--opt:size
--define:foo
--forceBuild
**Note**: In general, the *define* switches can also be set in
NimScripts using ``switch`` or ``--``, as shown in above
examples. Only the ``release`` define (``-d:release``) cannot be set
in NimScripts.
NimScript as a build tool
=========================
The ``task`` template that the ``system`` module defines allows a NimScript
file to be used as a build tool. The following example defines a
task ``build`` that is an alias for the ``c`` command:
.. code-block:: nim
task build, "builds an example":
setCommand "c"
In fact, as a convention the following tasks should be available:
========= ===================================================
Task Description
========= ===================================================
``help`` List all the available NimScript tasks along with their docstrings.
``build`` Build the project with the required
backend (``c``, ``cpp`` or ``js``).
``tests`` Runs the tests belonging to the project.
``bench`` Runs benchmarks belonging to the project.
========= ===================================================
Look at the module `distros <distros.html>`_ for some support of the
OS's native package managers.
Nimble integration
==================
See the `Nimble readme <https://github.com/nim-lang/nimble#readme>`_
for more information.
Standalone NimScript
====================
NimScript can also be used directly as a portable replacement for Bash and
Batch files. Use ``nim myscript.nims`` to run ``myscript.nims``. For example,
installation of Nimble could be accomplished with this simple script:
.. code-block:: nim
mode = ScriptMode.Verbose
var id = 0
while dirExists("nimble" & $id):
inc id
exec "git clone https://github.com/nim-lang/nimble.git nimble" & $id
withDir "nimble" & $id & "/src":
exec "nim c nimble"
mvFile "nimble" & $id & "/src/nimble".toExe, "bin/nimble".toExe
On Unix, you can also use the shebang ``#!/usr/bin/env nim``, as long as your filename
ends with ``.nims``:
.. code-block:: nim
#!/usr/bin/env nim
mode = ScriptMode.Silent
echo "hello world"
Use ``#!/usr/bin/env -S nim --hints:off`` to disable hints.
Benefits
========
Cross-Platform
--------------
It is a cross-platform scripting language that can run where Nim can run,
e.g. you can not run Batch or PowerShell on Linux or Mac,
the Bash for Linux might not run on Mac,
there are no unit tests tools for Batch, etc.
NimScript can detect on which platform, operating system,
architecture, and even which Linux distribution is running on,
allowing the same script to support a lot of systems.
See the following (incomplete) example:
.. code-block:: nim
import distros
# Architectures.
if defined(amd64):
echo "Architecture is x86 64Bits"
elif defined(i386):
echo "Architecture is x86 32Bits"
elif defined(arm):
echo "Architecture is ARM"
# Operating Systems.
if defined(linux):
echo "Operating System is GNU Linux"
elif defined(windows):
echo "Operating System is Microsoft Windows"
elif defined(macosx):
echo "Operating System is Apple OS X"
# Distros.
if detectOs(Ubuntu):
echo "Distro is Ubuntu"
elif detectOs(ArchLinux):
echo "Distro is ArchLinux"
elif detectOs(Debian):
echo "Distro is Debian"
Uniform Syntax
--------------
The syntax, style, and rest of the ecosystem is the same as for compiled Nim,
that means there is nothing new to learn, no context switch for developers.
Powerful Metaprogramming
------------------------
NimScript can use Nim's templates, macros, types, concepts, effect tracking system, and more,
you can create modules that work on compiled Nim and also on interpreted NimScript.
``func`` will still check for side effects, ``debugEcho`` also works as expected,
making it ideal for functional scripting metaprogramming.
This is an example of a third party module that uses macros and templates to
translate text strings on unmodified NimScript:
.. code-block:: nim
import nimterlingua
nimterlingua("translations.cfg")
echo "cat" # Run with -d:RU becomes "kot", -d:ES becomes "gato", ...
translations.cfg
.. code-block:: none
[cat]
ES = gato
PT = minino
RU = kot
FR = chat
* `Nimterlingua <https://nimble.directory/pkg/nimterlingua>`_
Graceful Fallback
-----------------
Some features of compiled Nim may not work on NimScript,
but often a graceful and seamless fallback degradation is used.
See the following NimScript:
.. code-block:: nim
if likely(true):
discard
elif unlikely(false):
discard
proc foo() {.compiletime.} = echo NimVersion
static:
echo CompileDate
``likely()``, ``unlikely()``, ``static:`` and ``{.compiletime.}``
will produce no code at all when run on NimScript,
but still no error nor warning is produced and the code just works.
Evolving Scripting language
---------------------------
NimScript evolves together with Nim,
`occasionally new features might become available on NimScript <https://github.com/nim-lang/Nim/pulls?utf8=%E2%9C%93&q=nimscript>`_ ,
adapted from compiled Nim or added as new features on both.
Scripting Language with a Package Manager
-----------------------------------------
You can create your own modules to be compatible with NimScript,
and check `Nimble <https://nimble.directory>`_
to search for third party modules that may work on NimScript.
DevOps Scripting
----------------
You can use NimScript to deploy to production, run tests, build projects, do benchmarks,
generate documentation, and all kinds of DevOps/SysAdmin specific tasks.
* `An example of a third party NimScript that can be used as a project-agnostic tool. <https://github.com/kaushalmodi/nim_config#list-available-tasks>`_
|