Panoramica della lingua Nim
Nim 2.2 — linguaggio di sistema | Sintassi simile a Python | Backend C/JS/LLVM | GC opzionale | metaprogrammazione tramite macro
Paradigma
Multi-paradigma: imperativo, funzionale, orientato agli oggetti (tramite la sintassi della chiamata al metodo), metaprogrammazione. Tipizzazione statica con inferenza completa (tipo Hindley-Milner), equivalenza di tipo strutturale. Compilazione tramite C, C++, JavaScript o LLVM. Le macro basate su AST vengono eseguite in fase di compilazione.
Tipi
| Categoria |
Tipi |
| Firmato int |
int8 int16 int32 int64 int (a seconda della piattaforma) |
| Intero non firmato |
uint8 uint16 uint32 uint64 uint |
| Galleggiante |
float32 float64 |
| Bool |
bool |
| Car |
char (1 byte) |
| Stringa |
string (mutabile, con prefisso di lunghezza) |
| Stringa di C |
cstring (con terminazione null) |
| Matrice |
array[N, T] array[T] |
| Sequenza |
seq[T] (array dinamico, gestito da GC) |
| Tupla |
(T1, T2) / tuple[a: T1, b: T2] |
| Oggetto |
object / ref object (heap + GC per impostazione predefinita) |
| Enum |
enum { variant, variant2 } |
| Gamma |
range[0..100] (sottointervallo) |
| Impostato |
set[T] (bitfield, fino a 256 elementi) |
| Puntatore |
ptr T |
| Riferimento |
ref T (tracciato GC) |
| Facoltativo |
Option[T] (da std) |
| Risultato |
Result[T, E] |
| Distinto |
distinct T (involucro nuovo tipo) |
| Digitare la classe |
Concept/generic vincolo |
| Vuoto |
void (tipo di ritorno) |
| Mai |
never (divergente) |
Dichiarazioni
| Costruisci |
Sintassi |
Note |
| Funzione |
proc name(params): Ret = body |
|
| Metodo |
proc name(self: T; params): Ret = body |
|
| Modello |
template name(params): untyped = body |
Sostituzione dell'AST |
| Macro |
macro name(params): untyped = body |
Manipolazione dell'AST |
| Variabile |
let x = expr |
Immutabile |
| Mutevole |
var x = expr |
|
| Costante |
const NAME = expr |
In fase di compilazione |
| Lascia (runtime) |
let x: T = expr |
|
| Oggetto |
type Name = object |
Tipo di valore |
| Oggetto rif |
type Name = ref object |
Allocato nell'heap |
| Tupla |
type Name = tuple[a: T, b: U] |
|
| Enum |
type Name = enum { a, b, c } |
|
| Unione |
type Name = object { case tag: T of ... } |
Variant/SUM tipo |
| Digita l'alias |
type Name = T |
|
| Importa |
import module / from module import name |
|
| Includi |
include "file.nim" |
Inclusione testuale |
| Tipo di processo |
type Handler = proc(params): Ret |
|
Flusso di controllo
| Costruisci |
Sintassi |
Note |
| Se |
if cond: ... else: ... |
|
| Se (espressione) |
let x = if cond: a else: b |
|
| Caso |
case expr: of val: ... else: ... |
Esauriente |
| Mentre |
while cond: ... |
|
| Per |
for x in iterable: ... |
|
| Per (intervallo) |
for i in 0..<n: ... |
|
| Per (contato) |
for i, x in enumerate(arr): ... |
|
| Per (coppie) |
for k, v in pairs(table): ... |
|
| Blocca |
block label: ... |
Blocco denominato |
| Pausa |
break label |
|
| Continua |
continue |
|
| Ritorno |
return expr |
|
| Rendimento |
yield expr |
Negli iteratori |
| Prova |
try: ... except E: ... finally: ... |
|
| Differire |
defer: expr |
Esegui all'uscita dall'ambito |
| Scartare |
discard expr |
Ignora il risultato |
Caratteristiche del caso (corrispondenza).
- Condizioni diramazione:
of val:, of val1, val2:, of 0..10:
- Modelli di intervallo, appartenenza a set, corrispondenza di tipi
of T(someField): - corrispondenza del modello con rilegatura
- Controllo di esaustività per le enumerazioni
Operatori
| Categoria |
Operatori |
| Aritmetica |
+ - * / div mod ^ (xor) |
| Confronto |
== != < > <= >= |
| Logico |
and or not xor |
| Bit per bit |
and or not xor shl shr asr |
| Impostato |
+ - * (intersezione) < <= (sottoinsieme) |
| Identità |
is (controllo tipo) of (controllo sottotipo) |
| Varie |
.. (intervallo) ..< $ (stringificazione) @ (prefisso seq) & (stringa concat) |
| Indirizzo |
addr x |
| Deref |
p[] |
| Freccia |
=> (ramo scatola, lambda) |
Sovraccarico degli operatori
È possibile eseguire l'overload di qualsiasi operatore: `+`, `*`, `in`, ecc. Gli operatori personalizzati possono essere definiti con la notazione backtick.
Sintassi della chiamata al metodo
# 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"
Generici
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
Memoria e GC
| Categoria |
Comportamento |
| Pila |
Tipi di valore (object, tuple, array) |
| Mucchio (GC) |
ref object, seq, string, pointer to ref |
| Heap (manuale) |
ptr T tramite alloc/dealloc |
| GC |
Opzionale: --gc:arc, --gc:orc, --gc:markandsweep, --gc:boehm, --gc:none |
ARC/ORC (da Nim 2.0)
--gc:arc: conteggio deterministico dei riferimenti (nessun raccoglitore di cicli)
--gc:orc: ARC + collettore di cicli opzionale
{.acyclic.} pragma per tipi senza ciclo
sink parametri per la semantica dello spostamento
cursor annotazione per una semantica simile al prestito
Memoria manuale
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")
Funzionalità in fase di compilazione
static[T] — forzare la valutazione in fase di compilazione
when - condizionale in fase di compilazione (come #if in C)
const — costante in fase di compilazione con semantica Nim completa
macro — Trasformazione del codice a livello AST
template — sostituzione a livello di sintassi
{.pragma.} — pragma definibili dall'utente
compileTime - esegui il codice in fase di compilazione
import macros — AST construction/manipulation
Libreria standard (selezionata)
| Modulo |
Contenuto |
system |
Procedure, operatori e tipi integrati |
strutils |
divisione di stringhe, unione, ricerca, sostituzione, rimozione, formato, parseInt, toUpper |
sequtils |
mappa, filtra, piega, zip, tutto, qualsiasi, concatena, deduplica |
tables |
Table OrderedTable CountTable TableRef |
sets |
HashSet OrderedSet BitSet |
math |
sqrt, sin, cos, log, pow, casuale, Pi, Tau, Eulero |
os |
fileExists, dirExists, createDir, deleteFile, getEnv, sleep, commandLineParams |
osproc |
execCmd, execProcess, startProcess |
net |
Socket, connetti, invia, ricevi, ascolta, accetta |
asyncnet / asyncdispatch |
Asincrono I/O con async/await |
json |
parseJson, %* (costruttore), [] accesso, carino |
xmltree / parsexml |
Analisi e costruzione XML |
parseopt |
Analisi delle opzioni della riga di comando |
critbits |
Alberi critici |
sha1 / md5 / base64 |
Primitive crittografiche |
times |
DateTime, TimeInterval, ora, formato, analisi |
streams |
StringStream, FileStream, MemoryStream |
logging |
Registratore con livelli e gestori |
macros |
Tipi AST, quoteDo, newStmtList, genSym |
pegs / re |
Corrispondenza PEG e Regex |
distros |
--os:, --cpu: rilevamento |
endians |
Big-endian/little-endian conversione |
Gestione degli errori
# 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)
Compilazione
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
Flag di compilazione
--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
Gestore di pacchetti 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 configura i metadati del pacchetto, le dipendenze e le regole di creazione.
Interoperabilità 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
Funzionalità dell'interfaccia delle funzioni estranee
{.importc.} {.exportc.} {.header.} {.link.} {.nodecl.}
{.importcpp.} per interoperabilità C++
{.importobjc.} per Obiettivo-C
{.importjs.} per l'interoperabilità JavaScript
{.packed.} per layout struttura compatibile con ABI
{.union.} per raccordi a C
{.bitsize.} per campi di bit