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)

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)

Mémoire manuelle

var p = alloc(sizeof(int))
p[] = 42
dealloc(p)

Macros et métaprogrammation

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

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