Présentation du langage Nim
Nim 2.2 — langage système | Syntaxe de type Python | Moteurs C/JS/LLVM | CG en option | métaprogrammation via des macros
Paradigme
Multi-paradigme : impératif, fonctionnel, orienté objet (via la syntaxe d'appel de méthode), métaprogrammation. Typage statique avec inférence complète (de type Hindley-Milner), équivalence de type structurel. Compilation via C, C++, JavaScript ou LLVM. Les macros basées sur AST s'exécutent au moment de la compilation.
Espèces
| Catégorie |
Espèces |
| Signé en entier |
int8 int16 int32 int64 int (en fonction de la plate-forme) |
| Entier non signé |
uint8 uint16 uint32 uint64 uint |
| Flotteur |
float32 float64 |
| Booléen |
bool |
| Char |
char (1 octet) |
| Chaîne |
string (mutable, avec préfixe de longueur) |
| Chaîne C |
cstring (terminé par un caractère nul) |
| Tableau |
array[N, T] array[T] |
| Séquence |
seq[T] (tableau dynamique, géré par GC) |
| Tuple |
(T1, T2) / tuple[a: T1, b: T2] |
| Objet |
object / ref object (tas + GC par défaut) |
| Énumération |
enum { variant, variant2 } |
| Gamme |
range[0..100] (sous-gamme) |
| Ensemble |
set[T] (champ de bits, jusqu'à 256 éléments) |
| Pointeur |
ptr T |
| Référence |
ref T (tracé GC) |
| Facultatif |
Option[T] (à partir de la norme) |
| Résultat |
Result[T, E] |
| Distinct |
distinct T (emballage nouveau type) |
| Classe de type |
Concept/generic contrainte |
| Vide |
void (type de retour) |
| Jamais |
never (divergent) |
Déclarations
| Construire |
Syntaxe |
Remarques |
| Fonction |
proc name(params): Ret = body |
|
| Méthode |
proc name(self: T; params): Ret = body |
|
| Modèle |
template name(params): untyped = body |
Remplacement de l'AST |
| Macro |
macro name(params): untyped = body |
Manipulation de l'AST |
| Variable |
let x = expr |
Immuable |
| Mutable |
var x = expr |
|
| Constante |
const NAME = expr |
Au moment de la compilation |
| Laisser (exécution) |
let x: T = expr |
|
| Objet |
type Name = object |
Type de valeur |
| Objet de référence |
type Name = ref object |
Alloué par tas |
| Tuple |
type Name = tuple[a: T, b: U] |
|
| Énumération |
type Name = enum { a, b, c } |
|
| Syndicat |
type Name = object { case tag: T of ... } |
Variant/SUM taper |
| Tapez un alias |
type Name = T |
|
| Importer |
import module / from module import name |
|
| Inclure |
include "file.nim" |
Inclusion textuelle |
| Type de procédure |
type Handler = proc(params): Ret |
|
Flux de contrôle
| Construire |
Syntaxe |
Remarques |
| Si |
if cond: ... else: ... |
|
| Si (expression) |
let x = if cond: a else: b |
|
| Cas |
case expr: of val: ... else: ... |
exhaustif |
| Tandis que |
while cond: ... |
|
| Pour |
for x in iterable: ... |
|
| Pour (plage) |
for i in 0..<n: ... |
|
| Pour (compté) |
for i, x in enumerate(arr): ... |
|
| Pour (paires) |
for k, v in pairs(table): ... |
|
| Bloquer |
block label: ... |
Bloc nommé |
| Pause |
break label |
|
| Continuer |
continue |
|
| Retour |
return expr |
|
| Rendement |
yield expr |
Dans les itérateurs |
| Essayez |
try: ... except E: ... finally: ... |
|
| Différer |
defer: expr |
Exécuter à la sortie de la portée |
| Jeter |
discard expr |
Ignorer le résultat |
Caractéristiques du boîtier (correspondance)
- Conditions de branche :
of val:, of val1, val2:, of 0..10:
- Modèles de plage, appartenance à un ensemble, correspondance de type
of T(someField): — correspondance de motifs avec reliure
- exhaustivité vérifiée pour les énumérations
Opérateurs
| Catégorie |
Opérateurs |
| Arithmétique |
+ - * / div mod ^ (xor) |
| Comparaison |
== != < > <= >= |
| Logique |
and or not xor |
| Au niveau du bit |
and or not xor shl shr asr |
| Ensemble |
+ - * (intersection) < <= (sous-ensemble) |
| Identité |
is (vérification de type) of (vérification de sous-type) |
| Divers |
.. (plage) ..< $ (stringifier) @ (préfixe séq) & (concaténation de chaîne) |
| Adresse |
addr x |
| Déf. |
p[] |
| Flèche |
=> (branchement de cas, lambda) |
Surcharge de l'opérateur
N'importe quel opérateur peut être surchargé : `+`, `*`, `in`, etc. Les opérateurs personnalisés peuvent être définis avec une notation backtick.
Syntaxe des appels de méthode
# Object-oriented style
echo "hello".len()
x.addr().repr()
# Uniform Function Call Syntax (UFCS)
# Any proc can be called as method:
proc greet(s: string): string = "Hello " & s
"world".greet() # "Hello world"
Génériques
proc id[T](x: T): T = x
type
Pair[T, U] = object
first: T
second: U
# Concepts (type constraints)
proc sort[T: SomeOrdinal](arr: var seq[T]) = ...
proc hash[T: Hashable](x: T): int =
# T must implement Hashable concept
Mémoire et CPG
| Catégorie |
Comportement |
| Pile |
Types de valeur (object, tuple, array) |
| Tas (GC) |
ref object, seq, string, pointer to ref |
| Tas (manuel) |
ptr T via alloc/dealloc |
| CG |
En option : --gc:arc, --gc:orc, --gc:markandsweep, --gc:boehm, --gc:none |
ARC/ORC (depuis Nim 2.0)
--gc:arc: comptage de références déterministe (pas de collecteur de cycles)
--gc:orc: ARC + collecteur de cycle en option
{.acyclic.} pragma pour les types sans cycle
sink paramètres pour la sémantique de déplacement
cursor annotation pour une sémantique de type emprunt
Mémoire manuelle
var p = alloc(sizeof(int))
p[] = 42
dealloc(p)
import macros
macro assert(cond: untyped): untyped =
# AST manipulation at compile time
result = quote do:
if not `cond`:
echo "assertion failed: ", astToStr(`cond`)
quit(1)
# Usage
assert(1 + 1 == 3)
# Template (simpler than macro)
template repeat(n: int, body: untyped): untyped =
for i in 0..<n:
body
repeat(3, echo "hello")
Fonctionnalités au moment de la compilation
static[T] — forcer l'évaluation au moment de la compilation
when — conditionnel à la compilation (comme #if en C)
const — constante de compilation avec sémantique Nim complète
macro — Transformation de code au niveau AST
template — substitution au niveau de la syntaxe
{.pragma.} — pragmas définissables par l'utilisateur
compileTime - exécuter le code au moment de la compilation
import macros — AST construction/manipulation
Bibliothèque standard (sélectionnée)
| Module |
Contenu |
system |
Processus, opérateurs et types intégrés |
strutils |
scission de chaîne, jointure, recherche, remplacement, suppression, formatage, parseInt, toUpper |
sequtils |
mapper, filtrer, plier, compresser, tout, n'importe lequel, concaténer, dédupliquer |
tables |
Table OrderedTable CountTable TableRef |
sets |
HashSet OrderedSet BitSet |
math |
sqrt, sin, cos, log, pow, aléatoire, Pi, Tau, Euler |
os |
fileExists, dirExists, createDir, RemoveFile, getEnv, sleep, commandLineParams |
osproc |
execCmd, execProcess, startProcess |
net |
Prise, connexion, envoi, réception, écoute, acceptation |
asyncnet / asyncdispatch |
Asynchrone I/O avec async/await |
json |
parseJson, %* (constructeur), [] accès, joli |
xmltree / parsexml |
Analyse et construction XML |
parseopt |
Analyse des options de ligne de commande |
critbits |
Arbres à coups critiques |
sha1 / md5 / base64 |
Primitives cryptographiques |
times |
DateTime, TimeInterval, maintenant, formater, analyser |
streams |
StringStream, FileStream, MemoryStream |
logging |
Enregistreur avec niveaux et gestionnaires |
macros |
Types AST, quoteDo, newStmtList, genSym |
pegs / re |
Correspondance PEG et Regex |
distros |
--os:, --cpu: détection |
endians |
Big-endian/little-endian conversion |
Gestion des erreurs
# Exceptions (runtime)
try:
let f = open("file.txt")
defer: f.close()
echo f.readAll()
except IOError as e:
echo "IO error: ", e.msg
finally:
echo "done"
# Result type (no exception, Nim 2.0+)
from std/result import Result, Ok, Err
func div(a, b: int): Result[int, string] =
if b == 0:
return Err("division by zero")
return Ok(a div b)
# Raise exceptions
raise newException(ValueError, "invalid input")
# Option type
import std/options
let x: Option[int] = some(42)
let y: Option[int] = none(int)
Compilation
nim c file.nim # compile with C backend
nim cpp file.nim # compile with C++ backend
nim js file.nim # compile to JavaScript
nim r file.nim # compile + run
nim build # compile project (newer)
nimble build # compile with Nimble package
nim check file.nim # type-check only
nim doc file.nim # generate documentation
nim pretty file.nim # format code
Drapeaux de compilation
--opt:speed --opt:size --opt:none -d:release --gc:orc --gc:arc --gc:markandsweep --cc:clang --cc:gcc --mm:arc --threads:on --stackTrace:on --lineTrace:on --checks:on
Gestionnaire de paquets agile
nimble init # create package
nimble install <pkg> # install dependency
nimble build # build project
nimble test # run tests
nimble publish # publish to nimble registry
nimble.cfg configure les métadonnées, les dépendances et les règles de build du package.
Interopérabilité C
# Declare C function
proc printf(fmt: cstring): cint {.importc, varargs.}
# Import C library
proc sqrt(x: float64): float64 {.importc: "sqrt", header: "math.h".}
# Export to C
proc myFunc(a: cint): cint {.exportc.} = a * 2
# Inline C code
{.emit: """
static int add(int a, int b) { return a + b; }
""".}
proc add(a, b: cint): cint {.importc: "add".}
# C type mappings
# int → cint, char → cchar, void → pointer
# char* → cstring, struct → object {.pure, inheritable.}
# size_t → csize, size_t → csize_t
Fonctionnalités de l'interface de fonction étrangère
{.importc.} {.exportc.} {.header.} {.link.} {.nodecl.}
{.importcpp.} pour l'interopérabilité C++
{.importobjc.} pour Objective-C
{.importjs.} pour l'interopérabilité JavaScript
{.packed.} pour la disposition de structure compatible ABI
{.union.} pour raccords C
{.bitsize.} pour les champs de bits